Merge branch 'main' into sync-issue-pr-and-more

This commit is contained in:
Chongyi Zheng 2024-02-06 15:52:29 -05:00
commit 323215f788
No known key found for this signature in database
GPG Key ID: 4B90B77407DA2359
625 changed files with 7535 additions and 5138 deletions

View File

@ -723,6 +723,7 @@ rules:
unicorn/no-this-assignment: [2]
unicorn/no-typeof-undefined: [2]
unicorn/no-unnecessary-await: [2]
unicorn/no-unnecessary-polyfills: [2]
unicorn/no-unreadable-array-destructuring: [0]
unicorn/no-unreadable-iife: [2]
unicorn/no-unused-properties: [2]

View File

@ -35,7 +35,7 @@ jobs:
yaml: ${{ steps.changes.outputs.yaml }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v2
- uses: dorny/paths-filter@v3
id: changes
with:
filters: |

View File

@ -1,7 +1,7 @@
plugins:
- stylelint-declaration-strict-value
- stylelint-declaration-block-no-ignored-properties
- stylelint-stylistic
- "@stylistic/stylelint-plugin"
ignoreFiles:
- "**/*.go"
@ -17,6 +17,82 @@ overrides:
customSyntax: postcss-html
rules:
"@stylistic/at-rule-name-case": null
"@stylistic/at-rule-name-newline-after": null
"@stylistic/at-rule-name-space-after": null
"@stylistic/at-rule-semicolon-newline-after": null
"@stylistic/at-rule-semicolon-space-before": null
"@stylistic/block-closing-brace-empty-line-before": null
"@stylistic/block-closing-brace-newline-after": null
"@stylistic/block-closing-brace-newline-before": null
"@stylistic/block-closing-brace-space-after": null
"@stylistic/block-closing-brace-space-before": null
"@stylistic/block-opening-brace-newline-after": null
"@stylistic/block-opening-brace-newline-before": null
"@stylistic/block-opening-brace-space-after": null
"@stylistic/block-opening-brace-space-before": null
"@stylistic/color-hex-case": lower
"@stylistic/declaration-bang-space-after": never
"@stylistic/declaration-bang-space-before": null
"@stylistic/declaration-block-semicolon-newline-after": null
"@stylistic/declaration-block-semicolon-newline-before": null
"@stylistic/declaration-block-semicolon-space-after": null
"@stylistic/declaration-block-semicolon-space-before": never
"@stylistic/declaration-block-trailing-semicolon": null
"@stylistic/declaration-colon-newline-after": null
"@stylistic/declaration-colon-space-after": null
"@stylistic/declaration-colon-space-before": never
"@stylistic/function-comma-newline-after": null
"@stylistic/function-comma-newline-before": null
"@stylistic/function-comma-space-after": null
"@stylistic/function-comma-space-before": null
"@stylistic/function-max-empty-lines": 0
"@stylistic/function-parentheses-newline-inside": never-multi-line
"@stylistic/function-parentheses-space-inside": null
"@stylistic/function-whitespace-after": null
"@stylistic/indentation": 2
"@stylistic/linebreaks": null
"@stylistic/max-empty-lines": 1
"@stylistic/max-line-length": null
"@stylistic/media-feature-colon-space-after": null
"@stylistic/media-feature-colon-space-before": never
"@stylistic/media-feature-name-case": null
"@stylistic/media-feature-parentheses-space-inside": null
"@stylistic/media-feature-range-operator-space-after": always
"@stylistic/media-feature-range-operator-space-before": always
"@stylistic/media-query-list-comma-newline-after": null
"@stylistic/media-query-list-comma-newline-before": null
"@stylistic/media-query-list-comma-space-after": null
"@stylistic/media-query-list-comma-space-before": null
"@stylistic/no-empty-first-line": null
"@stylistic/no-eol-whitespace": true
"@stylistic/no-extra-semicolons": true
"@stylistic/no-missing-end-of-source-newline": null
"@stylistic/number-leading-zero": null
"@stylistic/number-no-trailing-zeros": null
"@stylistic/property-case": lower
"@stylistic/selector-attribute-brackets-space-inside": null
"@stylistic/selector-attribute-operator-space-after": null
"@stylistic/selector-attribute-operator-space-before": null
"@stylistic/selector-combinator-space-after": null
"@stylistic/selector-combinator-space-before": null
"@stylistic/selector-descendant-combinator-no-non-space": null
"@stylistic/selector-list-comma-newline-after": null
"@stylistic/selector-list-comma-newline-before": null
"@stylistic/selector-list-comma-space-after": always-single-line
"@stylistic/selector-list-comma-space-before": never-single-line
"@stylistic/selector-max-empty-lines": 0
"@stylistic/selector-pseudo-class-case": lower
"@stylistic/selector-pseudo-class-parentheses-space-inside": never
"@stylistic/selector-pseudo-element-case": lower
"@stylistic/string-quotes": double
"@stylistic/unicode-bom": null
"@stylistic/unit-case": lower
"@stylistic/value-list-comma-newline-after": null
"@stylistic/value-list-comma-newline-before": null
"@stylistic/value-list-comma-space-after": null
"@stylistic/value-list-comma-space-before": null
"@stylistic/value-list-max-empty-lines": 0
alpha-value-notation: null
annotation-no-unknown: true
at-rule-allowed-list: null
@ -137,82 +213,6 @@ rules:
selector-type-no-unknown: [true, {ignore: [custom-elements]}]
shorthand-property-no-redundant-values: true
string-no-newline: true
stylistic/at-rule-name-case: null
stylistic/at-rule-name-newline-after: null
stylistic/at-rule-name-space-after: null
stylistic/at-rule-semicolon-newline-after: null
stylistic/at-rule-semicolon-space-before: null
stylistic/block-closing-brace-empty-line-before: null
stylistic/block-closing-brace-newline-after: null
stylistic/block-closing-brace-newline-before: null
stylistic/block-closing-brace-space-after: null
stylistic/block-closing-brace-space-before: null
stylistic/block-opening-brace-newline-after: null
stylistic/block-opening-brace-newline-before: null
stylistic/block-opening-brace-space-after: null
stylistic/block-opening-brace-space-before: null
stylistic/color-hex-case: lower
stylistic/declaration-bang-space-after: never
stylistic/declaration-bang-space-before: null
stylistic/declaration-block-semicolon-newline-after: null
stylistic/declaration-block-semicolon-newline-before: null
stylistic/declaration-block-semicolon-space-after: null
stylistic/declaration-block-semicolon-space-before: never
stylistic/declaration-block-trailing-semicolon: null
stylistic/declaration-colon-newline-after: null
stylistic/declaration-colon-space-after: null
stylistic/declaration-colon-space-before: never
stylistic/function-comma-newline-after: null
stylistic/function-comma-newline-before: null
stylistic/function-comma-space-after: null
stylistic/function-comma-space-before: null
stylistic/function-max-empty-lines: 0
stylistic/function-parentheses-newline-inside: never-multi-line
stylistic/function-parentheses-space-inside: null
stylistic/function-whitespace-after: null
stylistic/indentation: 2
stylistic/linebreaks: null
stylistic/max-empty-lines: 1
stylistic/max-line-length: null
stylistic/media-feature-colon-space-after: null
stylistic/media-feature-colon-space-before: never
stylistic/media-feature-name-case: null
stylistic/media-feature-parentheses-space-inside: null
stylistic/media-feature-range-operator-space-after: always
stylistic/media-feature-range-operator-space-before: always
stylistic/media-query-list-comma-newline-after: null
stylistic/media-query-list-comma-newline-before: null
stylistic/media-query-list-comma-space-after: null
stylistic/media-query-list-comma-space-before: null
stylistic/no-empty-first-line: null
stylistic/no-eol-whitespace: true
stylistic/no-extra-semicolons: true
stylistic/no-missing-end-of-source-newline: null
stylistic/number-leading-zero: null
stylistic/number-no-trailing-zeros: null
stylistic/property-case: lower
stylistic/selector-attribute-brackets-space-inside: null
stylistic/selector-attribute-operator-space-after: null
stylistic/selector-attribute-operator-space-before: null
stylistic/selector-combinator-space-after: null
stylistic/selector-combinator-space-before: null
stylistic/selector-descendant-combinator-no-non-space: null
stylistic/selector-list-comma-newline-after: null
stylistic/selector-list-comma-newline-before: null
stylistic/selector-list-comma-space-after: always-single-line
stylistic/selector-list-comma-space-before: never-single-line
stylistic/selector-max-empty-lines: 0
stylistic/selector-pseudo-class-case: lower
stylistic/selector-pseudo-class-parentheses-space-inside: never
stylistic/selector-pseudo-element-case: lower
stylistic/string-quotes: double
stylistic/unicode-bom: null
stylistic/unit-case: lower
stylistic/value-list-comma-newline-after: null
stylistic/value-list-comma-newline-before: null
stylistic/value-list-comma-space-after: null
stylistic/value-list-comma-space-before: null
stylistic/value-list-max-empty-lines: 0
time-min-milliseconds: null
unit-allowed-list: null
unit-disallowed-list: null

View File

@ -110,7 +110,7 @@ See the [development setup instructions](https://docs.gitea.com/development/hack
### Backend
Go dependencies are managed using [Go Modules](https://golang.org/cmd/go/#hdr-Module_maintenance). \
Go dependencies are managed using [Go Modules](https://go.dev/cmd/go/#hdr-Module_maintenance). \
You can find more details in the [go mod documentation](https://go.dev/ref/mod) and the [Go Modules Wiki](https://github.com/golang/go/wiki/Modules).
Pull requests should only modify `go.mod` and `go.sum` where it is related to your change, be it a bugfix or a new feature. \
@ -167,7 +167,7 @@ Here's how to run the test suite:
| Command | Action | |
| :------------------------------------- | :----------------------------------------------- | ------------ |
|``make test[\#SpecificTestName]`` | run unit test(s) |
|``make test[\#SpecificTestName]`` | run unit test(s) | |
|``make test-sqlite[\#SpecificTestName]``| run [integration](tests/integration) test(s) for SQLite |[More details](tests/integration/README.md) |
|``make test-e2e-sqlite[\#SpecificTestName]``| run [end-to-end](tests/e2e) test(s) for SQLite |[More details](tests/e2e/README.md) |

View File

@ -25,17 +25,17 @@ COMMA := ,
XGO_VERSION := go-1.21.x
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.44.0
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.49.0
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.5.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.2
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.5
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.0.1
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.6.25
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.0.3
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.6.26
DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest

View File

@ -178,5 +178,5 @@ Looking for an overview of the interface? Check it out!
|![Dashboard](https://dl.gitea.com/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.com/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.com/screenshots/global_issues.png)|
|:---:|:---:|:---:|
|![Branches](https://dl.gitea.com/screenshots/branches.png)|![Web Editor](https://dl.gitea.com/screenshots/web_editor.png)|![Activity](https://dl.gitea.com/screenshots/activity.png)|
|![New Migration](https://dl.gitea.com/screenshots/migration.png)|![Migrating](https://dl.gitea.com/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)
![Pull Request Dark](https://dl.gitea.com/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.com/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.com/screenshots/diff_dark.png)|
|![New Migration](https://dl.gitea.com/screenshots/migration.png)|![Migrating](https://dl.gitea.com/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)|
|![Pull Request Dark](https://dl.gitea.com/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.com/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.com/screenshots/diff_dark.png)|

View File

@ -98,5 +98,5 @@ Fork -> Patch -> Push -> Pull Request
|![Dashboard](https://dl.gitea.com/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.com/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.com/screenshots/global_issues.png)|
|:---:|:---:|:---:|
|![Branches](https://dl.gitea.com/screenshots/branches.png)|![Web Editor](https://dl.gitea.com/screenshots/web_editor.png)|![Activity](https://dl.gitea.com/screenshots/activity.png)|
|![New Migration](https://dl.gitea.com/screenshots/migration.png)|![Migrating](https://dl.gitea.com/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)
![Pull Request Dark](https://dl.gitea.com/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.com/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.com/screenshots/diff_dark.png)|
|![New Migration](https://dl.gitea.com/screenshots/migration.png)|![Migrating](https://dl.gitea.com/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)|
|![Pull Request Dark](https://dl.gitea.com/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.com/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.com/screenshots/diff_dark.png)|

File diff suppressed because one or more lines are too long

View File

@ -50,6 +50,6 @@ func runGenerateActionsRunnerToken(c *cli.Context) error {
if extra.HasError() {
return handleCliResponseExtra(extra)
}
_, _ = fmt.Printf("%s\n", respText)
_, _ = fmt.Printf("%s\n", respText.Text)
return nil
}

View File

@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
@ -122,7 +123,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
log.Trace("Processing next %d repos of %d", len(repos), count)
for _, repo := range repos {
log.Trace("Synchronizing repo %s with path %s", repo.FullName(), repo.RepoPath())
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
if err != nil {
log.Warn("OpenRepository: %v", err)
continue

View File

@ -4,13 +4,14 @@
package cmd
import (
"context"
"errors"
"fmt"
user_model "code.gitea.io/gitea/models/user"
pwd "code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
user_service "code.gitea.io/gitea/services/user"
"github.com/urfave/cli/v2"
)
@ -32,6 +33,10 @@ var microcmdUserChangePassword = &cli.Command{
Value: "",
Usage: "New password to set for user",
},
&cli.BoolFlag{
Name: "must-change-password",
Usage: "User must change password",
},
},
}
@ -46,31 +51,32 @@ func runChangePassword(c *cli.Context) error {
if err := initDB(ctx); err != nil {
return err
}
if len(c.String("password")) < setting.MinPasswordLength {
return fmt.Errorf("Password is not long enough. Needs to be at least %d", setting.MinPasswordLength)
}
if !pwd.IsComplexEnough(c.String("password")) {
return errors.New("Password does not meet complexity requirements")
}
pwned, err := pwd.IsPwned(context.Background(), c.String("password"))
user, err := user_model.GetUserByName(ctx, c.String("username"))
if err != nil {
return err
}
if pwned {
return errors.New("The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password.\nFor more details, see https://haveibeenpwned.com/Passwords")
}
uname := c.String("username")
user, err := user_model.GetUserByName(ctx, uname)
if err != nil {
return err
}
if err = user.SetPassword(c.String("password")); err != nil {
return err
var mustChangePassword optional.Option[bool]
if c.IsSet("must-change-password") {
mustChangePassword = optional.Some(c.Bool("must-change-password"))
}
if err = user_model.UpdateUserCols(ctx, user, "passwd", "passwd_hash_algo", "salt"); err != nil {
return err
opts := &user_service.UpdateAuthOptions{
Password: optional.Some(c.String("password")),
MustChangePassword: mustChangePassword,
}
if err := user_service.UpdateAuth(ctx, user, opts); err != nil {
switch {
case errors.Is(err, password.ErrMinLength):
return fmt.Errorf("Password is not long enough. Needs to be at least %d", setting.MinPasswordLength)
case errors.Is(err, password.ErrComplexity):
return errors.New("Password does not meet complexity requirements")
case errors.Is(err, password.ErrIsPwned):
return errors.New("The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password.\nFor more details, see https://haveibeenpwned.com/Passwords")
default:
return err
}
}
fmt.Printf("%s's password has been successfully updated!\n", user.Name)

View File

@ -15,9 +15,9 @@ import (
"code.gitea.io/gitea/models/migrations"
migrate_base "code.gitea.io/gitea/models/migrations/base"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/doctor"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/doctor"
"github.com/urfave/cli/v2"
"xorm.io/xorm"

View File

@ -7,8 +7,8 @@ import (
"context"
"testing"
"code.gitea.io/gitea/modules/doctor"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/services/doctor"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v2"

View File

@ -78,6 +78,6 @@ func runKeys(c *cli.Context) error {
if extra.Error != nil {
return extra.Error
}
_, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString))
_, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString.Text))
return nil
}

View File

@ -45,6 +45,6 @@ func runSendMail(c *cli.Context) error {
if extra.HasError() {
return handleCliResponseExtra(extra)
}
_, _ = fmt.Printf("Sent %s email(s) to all users\n", respText)
_, _ = fmt.Printf("Sent %s email(s) to all users\n", respText.Text)
return nil
}

View File

@ -110,6 +110,9 @@ func migrateLFS(ctx context.Context, dstStorage storage.ObjectStorage) error {
func migrateAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.Iterate(ctx, nil, func(ctx context.Context, user *user_model.User) error {
if user.CustomAvatarRelativePath() == "" {
return nil
}
_, err := storage.Copy(dstStorage, user.CustomAvatarRelativePath(), storage.Avatars, user.CustomAvatarRelativePath())
return err
})
@ -117,6 +120,9 @@ func migrateAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error
func migrateRepoAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.Iterate(ctx, nil, func(ctx context.Context, repo *repo_model.Repository) error {
if repo.CustomAvatarRelativePath() == "" {
return nil
}
_, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath())
return err
})

View File

@ -431,7 +431,7 @@ SECRET_KEY =
;SECRET_KEY_URI = file:/etc/gitea/secret_key
;;
;; Secret used to validate communication within Gitea binary.
INTERNAL_TOKEN=
INTERNAL_TOKEN =
;;
;; Alternative location to specify internal token, instead of this file; you cannot specify both this and INTERNAL_TOKEN, and must pick one
;INTERNAL_TOKEN_URI = file:/etc/gitea/internal_token
@ -524,7 +524,7 @@ INTERNAL_TOKEN=
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Enables OAuth2 provider
ENABLE = true
ENABLED = true
;;
;; Algorithm used to sign OAuth2 tokens. Valid values: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, EdDSA
;JWT_SIGNING_ALGORITHM = RS256

View File

@ -95,6 +95,7 @@ Admin operations:
- Options:
- `--username value`, `-u value`: Username. Required.
- `--password value`, `-p value`: New password. Required.
- `--must-change-password`: If provided, the user is required to choose a new password after the login. Optional.
- Examples:
- `gitea admin user change-password --username myname --password asecurepassword`
- `must-change-password`:

View File

@ -1107,7 +1107,7 @@ This section only does "set" config, a removed config key from this section won'
## OAuth2 (`oauth2`)
- `ENABLE`: **true**: Enables OAuth2 provider.
- `ENABLED`: **true**: Enables OAuth2 provider.
- `ACCESS_TOKEN_EXPIRATION_TIME`: **3600**: Lifetime of an OAuth2 access token in seconds
- `REFRESH_TOKEN_EXPIRATION_TIME`: **730**: Lifetime of an OAuth2 refresh token in hours
- `INVALIDATE_REFRESH_TOKENS`: **false**: Check if refresh token has already been used

View File

@ -1043,7 +1043,7 @@ Gitea 创建以下非唯一队列:
## OAuth2 (`oauth2`)
- `ENABLE`: **true**启用OAuth2提供者。
- `ENABLED`: **true**启用OAuth2提供者。
- `ACCESS_TOKEN_EXPIRATION_TIME`**3600**OAuth2访问令牌的生命周期以秒为单位。
- `REFRESH_TOKEN_EXPIRATION_TIME`**730**OAuth2刷新令牌的生命周期以小时为单位。
- `INVALIDATE_REFRESH_TOKENS`**false**:检查刷新令牌是否已被使用。

View File

@ -27,14 +27,15 @@ GITEA_CUSTOM=/home/gitea/custom ./gitea web
## From Go language
As Gitea is written in Go, it uses some Go variables, such as:
As Gitea is written in Go, it uses some variables that influence the behaviour of Go's runtime, such as:
- `GOOS`
- `GOARCH`
- [`GOPATH`](https://golang.org/cmd/go/#hdr-GOPATH_environment_variable)
- `GOMEMLIMIT`
- `GOGC`
- `GOMAXPROCS`
- `GODEBUG`
For documentation about each of the variables available, refer to the
[official Go documentation](https://golang.org/cmd/go/#hdr-Environment_variables).
[official Go documentation on runtime environment variables](https://pkg.go.dev/runtime#hdr-Environment_Variables).
## Gitea files

View File

@ -29,9 +29,9 @@ GITEA_CUSTOM=/home/gitea/custom ./gitea web
* `GOOS`
* `GOARCH`
* [`GOPATH`](https://golang.org/cmd/go/#hdr-GOPATH_environment_variable)
* [`GOPATH`](https://go.dev/cmd/go/#hdr-GOPATH_environment_variable)
您可以在[官方文档](https://golang.org/cmd/go/#hdr-Environment_variables)中查阅这些配置参数的详细信息。
您可以在[官方文档](https://go.dev/cmd/go/#hdr-Environment_variables)中查阅这些配置参数的详细信息。
## Gitea 的文件目录

View File

@ -85,7 +85,7 @@ Text and macros for the mail body
Specifying a _subject_ section is optional (and therefore also the dash line separator). When used, the separator between
_subject_ and _mail body_ templates requires at least three dashes; no other characters are allowed in the separator line.
_Subject_ and _mail body_ are parsed by [Golang's template engine](https://golang.org/pkg/text/template/) and
_Subject_ and _mail body_ are parsed by [Golang's template engine](https://go.dev/pkg/text/template/) and
are provided with a _metadata context_ assembled for each notification. The context contains the following elements:
| Name | Type | Available | Usage |
@ -110,7 +110,7 @@ All names are case sensitive.
### The _subject_ part of the template
The template engine used for the mail _subject_ is golang's [`text/template`](https://golang.org/pkg/text/template/).
The template engine used for the mail _subject_ is golang's [`text/template`](https://go.dev/pkg/text/template/).
Please refer to the linked documentation for details about its syntax.
The _subject_ is built using the following steps:
@ -138,7 +138,7 @@ the two templates, even if a valid subject template is present.
### The _mail body_ part of the template
The template engine used for the _mail body_ is golang's [`html/template`](https://golang.org/pkg/html/template/).
The template engine used for the _mail body_ is golang's [`html/template`](https://go.dev/pkg/html/template/).
Please refer to the linked documentation for details about its syntax.
The _mail body_ is parsed after the mail subject, so there is an additional _metadata_ field which is
@ -146,7 +146,7 @@ the actual rendered subject, after all considerations.
The expected result is HTML (including structural elements like`<html>`, `<body>`, etc.). Styling
through `<style>` blocks, `class` and `style` attributes is possible. However, `html/template`
does some [automatic escaping](https://golang.org/pkg/html/template/#hdr-Contexts) that should be considered.
does some [automatic escaping](https://go.dev/pkg/html/template/#hdr-Contexts) that should be considered.
Attachments (such as images or external style sheets) are not supported. However, other templates can
be referenced too, for example to provide the contents of a `<style>` element in a centralized fashion.

View File

@ -81,7 +81,7 @@ custom/templates/mail/pull/comment.tmpl
指定 _主题_ 部分是可选的因此也是虚线分隔符。在使用时_主题_ 和 _邮件正文_ 模板之间的分隔符需要至少三个虚线;分隔符行中不允许使用其他字符。
_主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://golang.org/pkg/text/template/) 解析,并提供了为每个通知组装的 _元数据上下文_。上下文包含以下元素:
_主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/template/) 解析,并提供了为每个通知组装的 _元数据上下文_。上下文包含以下元素:
| 名称 | 类型 | 可用性 | 用途 |
| -------------------- | ------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@ -105,7 +105,7 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://golang.org/pkg/t
### 模板中的主题部分
用于邮件主题的模板引擎是 Golang 的 [`text/template`](https://golang.org/pkg/text/template/)。
用于邮件主题的模板引擎是 Golang 的 [`text/template`](https://go.dev/pkg/text/template/)。
有关语法的详细信息,请参阅链接的文档。
主题构建的步骤如下:
@ -130,12 +130,12 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://golang.org/pkg/t
### 模板中的邮件正文部分
用于邮件正文的模板引擎是 Golang 的 [`html/template`](https://golang.org/pkg/html/template/)。
用于邮件正文的模板引擎是 Golang 的 [`html/template`](https://go.dev/pkg/html/template/)。
有关语法的详细信息,请参阅链接的文档。
邮件正文在邮件主题之后进行解析,因此还有一个额外的 _元数据_ 字段,即在考虑所有情况之后实际呈现的主题。
期望的结果是 HTML包括结构元素如`<html>``<body>`等)。可以通过 `<style>` 块、`class` 和 `style` 属性进行样式设置。但是,`html/template` 会进行一些 [自动转义](https://golang.org/pkg/html/template/#hdr-Contexts),需要考虑这一点。
期望的结果是 HTML包括结构元素如`<html>``<body>`等)。可以通过 `<style>` 块、`class` 和 `style` 属性进行样式设置。但是,`html/template` 会进行一些 [自动转义](https://go.dev/pkg/html/template/#hdr-Contexts),需要考虑这一点。
不支持附件(例如图像或外部样式表)。但是,也可以引用其他模板,例如以集中方式提供 `<style>` 元素的内容。外部模板必须放置在 `custom/mail` 下,并相对于该目录引用。例如,可以使用 `{{template styles/base}}` 包含 `custom/mail/styles/base.tmpl`

View File

@ -65,14 +65,17 @@ Recommended implementations:
* Vue + Vanilla JS
* Fomantic-UI (jQuery)
* htmx (partial page reloads for otherwise static components)
* Vanilla JS
Discouraged implementations:
* Vue + Fomantic-UI (jQuery)
* jQuery + Vanilla JS
* htmx + any other framework which requires heavy JS code, or unnecessary features like htmx scripting (`hx-on`)
To make UI consistent, Vue components can use Fomantic-UI CSS classes.
We use htmx for simple interactions. You can see an example for simple interactions where htmx should be used in this [PR](https://github.com/go-gitea/gitea/pull/28908). Do not use htmx if you require more advanced reactivity, use another framework (Vue/Vanilla JS).
Although mixing different frameworks is discouraged,
it should also work if the mixing is necessary and the code is well-designed and maintainable.

View File

@ -25,7 +25,7 @@ To get a quick working development environment you could use Gitpod.
## Installing go
You should [install go](https://golang.org/doc/install) and set up your go
You should [install go](https://go.dev/doc/install) and set up your go
environment correctly.
Next, [install Node.js with npm](https://nodejs.org/en/download/) which is

View File

@ -25,7 +25,7 @@ menu:
## 安装 Golang
您需要 [安装 go]( https://golang.org/doc/install ) 并设置您的 go 环境。
您需要 [安装 go]( https://go.dev/doc/install ) 并设置您的 go 环境。
接下来,[使用 npm 安装 Node.js](https://nodejs.org/en/download/) ,这是构建
JavaScript 和 CSS 文件的必要工具。最低支持的 Node.js 版本是 @minNodeVersion@

View File

@ -17,7 +17,7 @@ menu:
# Installation from source
You should [install go](https://golang.org/doc/install) and set up your go
You should [install go](https://go.dev/doc/install) and set up your go
environment correctly. In particular, it is recommended to set the `$GOPATH`
environment variable and to add the go bin directory or directories
`${GOPATH//://bin:}/bin` to the `$PATH`. See the Go wiki entry for
@ -82,7 +82,7 @@ git checkout v@version@ # or git checkout pr-xyz
To build from source, the following programs must be present on the system:
- `go` @minGoVersion@ or higher, see [here](https://golang.org/dl/)
- `go` @minGoVersion@ or higher, see [here](https://go.dev/dl/)
- `node` @minNodeVersion@ or higher with `npm`, see [here](https://nodejs.org/en/download/)
- `make`, see [here](development/hacking-on-gitea.md#installing-make)
@ -119,7 +119,7 @@ TAGS="bindata sqlite sqlite_unlock_notify" make build
The `build` target is split into two sub-targets:
- `make backend` which requires [Go @minGoVersion@](https://golang.org/dl/) or greater.
- `make backend` which requires [Go @minGoVersion@](https://go.dev/dl/) or greater.
- `make frontend` which requires [Node.js @minNodeVersion@](https://nodejs.org/en/download/) or greater.
If pre-built frontend files are present it is possible to only build the backend:
@ -165,7 +165,7 @@ Running `gitea help` will allow you to review what the computed settings will be
## Cross Build
The `go` compiler toolchain supports cross-compiling to different architecture targets that are supported by the toolchain. See [`GOOS` and `GOARCH` environment variable](https://golang.org/doc/install/source#environment) for the list of supported targets. Cross compilation is helpful if you want to build Gitea for less-powerful systems (such as Raspberry Pi).
The `go` compiler toolchain supports cross-compiling to different architecture targets that are supported by the toolchain. See [`GOOS` and `GOARCH` environment variable](https://go.dev/doc/install/source#environment) for the list of supported targets. Cross compilation is helpful if you want to build Gitea for less-powerful systems (such as Raspberry Pi).
To cross build Gitea with build tags (`TAGS`), you also need a C cross compiler which targets the same architecture as selected by the `GOOS` and `GOARCH` variables. For example, to cross build for Linux ARM64 (`GOOS=linux` and `GOARCH=arm64`), you need the `aarch64-unknown-linux-gnu-gcc` cross compiler. This is required because Gitea build tags uses `cgo`'s foreign-function interface (FFI).

View File

@ -62,7 +62,7 @@ git checkout v@version@ # or git checkout pr-xyz
要从源代码进行构建,系统必须预先安装以下程序:
- `go` @minGoVersion@ 或更高版本,请参阅 [这里](https://golang.org/dl/)
- `go` @minGoVersion@ 或更高版本,请参阅 [这里](https://go.dev/dl/)
- `node` @minNodeVersion@ 或更高版本,并且安装 `npm`, 请参阅 [这里](https://nodejs.org/zh-cn/download/)
- `make`, 请参阅 [这里](development/hacking-on-gitea.md)
@ -128,7 +128,7 @@ Gitea 将从`CustomPath`中查找许多信息。默认的,这会在运行 Gite
## 交叉编译
`go`编译器工具链支持将代码交叉编译到不同的目标架构上。请参考[`GOOS`和`GOARCH`环境变量](https://golang.org/doc/install/source#environment) 以获取支持的目标列表。如果您想为性能较弱的系统(如树莓派)构建 Gitea交叉编译非常有用。
`go`编译器工具链支持将代码交叉编译到不同的目标架构上。请参考[`GOOS`和`GOARCH`环境变量](https://go.dev/doc/install/source#environment) 以获取支持的目标列表。如果您想为性能较弱的系统(如树莓派)构建 Gitea交叉编译非常有用。
要使用构建标签(`TAGS`进行交叉编译Gitea您还需要一个 C 交叉编译器,该编译器的目标架构与`GOOS`和`GOARCH`变量选择的架构相同。例如,要为 Linux ARM64`GOOS=linux`和`GOARCH=arm64`)进行交叉编译,您需要`aarch64-unknown-linux-gnu-gcc`交叉编译器。这是因为 Gitea 构建标签使用了`cgo`的外部函数接口FFI

View File

@ -132,7 +132,7 @@ Gitea Actions目前不支持此功能。
如果你使用 `uses: actions/checkout@v4`Gitea将会从 https://github.com/actions/checkout.git 下载这个 actions 项目。
如果你想要从另外一个 Git服务下载actions你只需要使用绝对URL `uses: https://gitea.com/actions/checkout@v4` 来下载。
如果你的 Gitea 实例是部署在一个互联网限制的网络中,有可以使用绝对地址来下载 actions。你也可以讲配置项修改为 `[actions].DEFAULT_ACTIONS_URL = self`。这样所有的相对路径的actions引用将不再会从 github.com 去下载,而会从这个 Gitea 实例自己的仓库中去下载。例如: `uses: actions/checkout@v4` 将会从 `[server].ROOT_URL`/actions/checkout.git 这个地址去下载 actions。
如果你的 Gitea 实例是部署在一个互联网限制的网络中,也可以使用绝对地址来下载 actions。你也可以将配置项修改为 `[actions].DEFAULT_ACTIONS_URL = self`。这样所有的相对路径的actions引用将不再会从 github.com 去下载,而会从这个 Gitea 实例自己的仓库中去下载。例如: `uses: actions/checkout@v4` 将会从 `[server].ROOT_URL`/actions/checkout.git 这个地址去下载 actions。
设置`[actions].DEFAULT_ACTIONS_URL`进行配置。请参阅[配置备忘单](administration/config-cheat-sheet.md#actions-actions)。

View File

@ -102,7 +102,7 @@ DELETE https://gitea.example.com/api/packages/{owner}/alpine/{branch}/{repositor
| `branch` | The branch to use. |
| `repository` | The repository to use. |
| `architecture` | The package architecture. |
| `filename` | The file to delete.
| `filename` | The file to delete. |
Example request using HTTP Basic authentication:

View File

@ -24,16 +24,26 @@ The following examples use `dnf`.
## Configuring the package registry
To register the RPM registry add the url to the list of known apt sources:
To register the RPM registry add the url to the list of known sources:
```shell
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo
```
| Placeholder | Description |
| ----------- |----------------------------------------------------|
| `owner` | The owner of the package. |
| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
| Placeholder | Description |
| ----------- | ----------- |
| `owner` | The owner of the package. |
| `group` | Optional: Everything, e.g. empty, `el7`, `rocky/el9`, `test/fc38`. |
Example:
```shell
# without a group
dnf config-manager --add-repo https://gitea.example.com/api/packages/testuser/rpm.repo
# with the group 'centos/el7'
dnf config-manager --add-repo https://gitea.example.com/api/packages/testuser/rpm/centos/el7.repo
```
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
@ -41,7 +51,7 @@ If the registry is private, provide credentials in the url. You can use a passwo
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo
```
You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.repos.d` too.
You have to add the credentials to the urls in the created `.repo` file in `/etc/yum.repos.d` too.
## Publish a package
@ -54,11 +64,17 @@ PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload
| Parameter | Description |
| --------- | ----------- |
| `owner` | The owner of the package. |
| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
| `group` | Optional: Everything, e.g. empty, `el7`, `rocky/el9`, `test/fc38`. |
Example request using HTTP Basic authentication:
```shell
# without a group
curl --user your_username:your_password_or_token \
--upload-file path/to/file.rpm \
https://gitea.example.com/api/packages/testuser/rpm/upload
# with the group 'centos/el7'
curl --user your_username:your_password_or_token \
--upload-file path/to/file.rpm \
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/upload
@ -83,17 +99,22 @@ To delete an RPM package perform a HTTP DELETE operation. This will delete the p
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture}
```
| Parameter | Description |
|-------------------|----------------------------|
| `owner` | The owner of the package. |
| `group` | The package group . |
| `package_name` | The package name. |
| `package_version` | The package version. |
| `architecture` | The package architecture. |
| Parameter | Description |
| ----------------- | ----------- |
| `owner` | The owner of the package. |
| `group` | Optional: The package group. |
| `package_name` | The package name. |
| `package_version` | The package version. |
| `architecture` | The package architecture. |
Example request using HTTP Basic authentication:
```shell
# without a group
curl --user your_username:your_token_or_password -X DELETE \
https://gitea.example.com/api/packages/testuser/rpm/package/test-package/1.0.0/x86_64
# with the group 'centos/el7'
curl --user your_username:your_token_or_password -X DELETE \
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64
```

View File

@ -19,3 +19,7 @@ To display a Markdown file in your Gitea user or organization profile page, crea
Gitea will automatically display the contents of the file on your profile, in a new "Overview" above your repositories.
Making the `.profile` repository private will hide the Profile README.
Example of user with `.profile/README.md`:
![profile readme screenshot](/images/usage/profile-readme.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

102
go.mod
View File

@ -5,7 +5,7 @@ go 1.21
require (
code.gitea.io/actions-proto-go v0.3.1
code.gitea.io/gitea-vet v0.2.3
code.gitea.io/sdk/gitea v0.17.0
code.gitea.io/sdk/gitea v0.17.1
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669
gitea.com/go-chi/cache v0.2.0
@ -21,7 +21,7 @@ require (
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.3.10
github.com/bufbuild/connect-go v1.10.0
github.com/buildkite/terminal-to-html/v3 v3.10.0
github.com/buildkite/terminal-to-html/v3 v3.10.1
github.com/caddyserver/certmagic v0.20.0
github.com/chi-middleware/proxy v1.1.1
github.com/denisenkom/go-mssqldb v0.12.3
@ -36,27 +36,27 @@ require (
github.com/ethantkoenig/rupture v1.0.1
github.com/felixge/fgprof v0.9.3
github.com/fsnotify/fsnotify v1.7.0
github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46
github.com/gliderlabs/ssh v0.3.6
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
github.com/go-chi/chi/v5 v5.0.10
github.com/go-chi/chi/v5 v5.0.11
github.com/go-chi/cors v1.2.1
github.com/go-co-op/gocron v1.37.0
github.com/go-enry/go-enry/v2 v2.8.6
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
github.com/go-git/go-billy/v5 v5.5.0
github.com/go-git/go-git/v5 v5.9.0
github.com/go-git/go-git/v5 v5.11.0
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-sql-driver/mysql v1.7.1
github.com/go-swagger/go-swagger v0.30.5
github.com/go-testfixtures/testfixtures/v3 v3.9.0
github.com/go-webauthn/webauthn v0.9.4
github.com/go-webauthn/webauthn v0.10.0
github.com/gobwas/glob v0.2.3
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v5 v5.2.0
github.com/google/go-github/v57 v57.0.0
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815
github.com/google/uuid v1.5.0
github.com/gorilla/feeds v1.1.2
github.com/gorilla/sessions v1.2.2
@ -74,7 +74,7 @@ require (
github.com/markbates/goth v1.78.0
github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-sqlite3 v1.14.19
github.com/meilisearch/meilisearch-go v0.26.0
github.com/meilisearch/meilisearch-go v0.26.1
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.26
github.com/minio/minio-go/v7 v7.0.66
@ -84,44 +84,44 @@ require (
github.com/niklasfasching/go-org v1.7.0
github.com/olivere/elastic/v7 v7.0.32
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0-rc5
github.com/opencontainers/image-spec v1.1.0-rc6
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.17.0
github.com/prometheus/client_golang v1.18.0
github.com/quasoft/websspi v1.1.2
github.com/redis/go-redis/v9 v9.3.0
github.com/redis/go-redis/v9 v9.4.0
github.com/robfig/cron/v3 v3.0.1
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
github.com/sassoftware/go-rpmutils v0.2.0
github.com/sassoftware/go-rpmutils v0.2.1-0.20240124161140-277b154961dd
github.com/sergi/go-diff v1.3.1
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92
github.com/stretchr/testify v1.8.4
github.com/syndtr/goleveldb v1.0.0
github.com/tstranex/u2f v1.0.0
github.com/ulikunitz/xz v0.5.11
github.com/urfave/cli/v2 v2.26.0
github.com/xanzy/go-gitlab v0.95.2
github.com/urfave/cli/v2 v2.27.1
github.com/xanzy/go-gitlab v0.96.0
github.com/xeipuuv/gojsonschema v1.2.0
github.com/yohcop/openid-go v1.0.1
github.com/yuin/goldmark v1.6.0
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
github.com/yuin/goldmark-meta v1.1.0
golang.org/x/crypto v0.17.0
golang.org/x/image v0.14.0
golang.org/x/net v0.19.0
golang.org/x/oauth2 v0.15.0
golang.org/x/sys v0.15.0
golang.org/x/crypto v0.18.0
golang.org/x/image v0.15.0
golang.org/x/net v0.20.0
golang.org/x/oauth2 v0.16.0
golang.org/x/sys v0.16.0
golang.org/x/text v0.14.0
golang.org/x/tools v0.16.1
google.golang.org/grpc v1.60.0
google.golang.org/protobuf v1.31.0
golang.org/x/tools v0.17.0
google.golang.org/grpc v1.60.1
google.golang.org/protobuf v1.32.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v3 v3.0.1
mvdan.cc/xurls/v2 v2.5.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.13
xorm.io/xorm v1.3.7-0.20240101024435-4992cba040fe
xorm.io/xorm v1.3.7
)
require (
@ -129,29 +129,28 @@ require (
cloud.google.com/go/compute/metadata v0.2.3 // indirect
dario.cat/mergo v1.0.0 // indirect
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
github.com/ClickHouse/ch-go v0.61.0 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.16.0 // indirect
github.com/ClickHouse/ch-go v0.61.1 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.17.1 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/RoaringBitmap/roaring v1.7.0 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.12.0 // indirect
github.com/blevesearch/bleve_index_api v1.1.4 // indirect
github.com/blevesearch/geo v0.1.18 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/blevesearch/bleve_index_api v1.1.5 // indirect
github.com/blevesearch/geo v0.1.19 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
github.com/blevesearch/gtreap v0.1.1 // indirect
github.com/blevesearch/mmap-go v1.0.4 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.2.5 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.2.6 // indirect
github.com/blevesearch/segment v0.9.1 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
@ -185,18 +184,18 @@ require (
github.com/go-faster/city v1.0.1 // indirect
github.com/go-faster/errors v0.7.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-openapi/analysis v0.21.5 // indirect
github.com/go-openapi/analysis v0.22.2 // indirect
github.com/go-openapi/errors v0.21.0 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-openapi/jsonpointer v0.20.1 // indirect
github.com/go-openapi/jsonreference v0.20.3 // indirect
github.com/go-openapi/loads v0.21.3 // indirect
github.com/go-openapi/jsonpointer v0.20.2 // indirect
github.com/go-openapi/jsonreference v0.20.4 // indirect
github.com/go-openapi/loads v0.21.5 // indirect
github.com/go-openapi/runtime v0.26.2 // indirect
github.com/go-openapi/spec v0.20.12 // indirect
github.com/go-openapi/strfmt v0.21.10 // indirect
github.com/go-openapi/swag v0.22.5 // indirect
github.com/go-openapi/validate v0.22.4 // indirect
github.com/go-webauthn/x v0.1.5 // indirect
github.com/go-openapi/spec v0.20.14 // indirect
github.com/go-openapi/strfmt v0.22.0 // indirect
github.com/go-openapi/swag v0.22.7 // indirect
github.com/go-openapi/validate v0.22.6 // indirect
github.com/go-webauthn/x v0.1.6 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
@ -228,9 +227,8 @@ require (
github.com/markbates/going v1.0.3 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mholt/acmez v1.2.0 // indirect
github.com/miekg/dns v1.1.57 // indirect
github.com/miekg/dns v1.1.58 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
@ -243,13 +241,13 @@ require (
github.com/oklog/ulid v1.3.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/paulmach/orb v0.10.0 // indirect
github.com/paulmach/orb v0.11.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pierrec/lz4/v4 v4.1.19 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/common v0.46.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rhysd/actionlint v1.6.26 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
@ -284,17 +282,17 @@ require (
github.com/zeebo/blake3 v0.2.3 // indirect
go.etcd.io/bbolt v1.3.8 // indirect
go.mongodb.org/mongo-driver v1.13.1 // indirect
go.opentelemetry.io/otel v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.opentelemetry.io/otel v1.22.0 // indirect
go.opentelemetry.io/otel/trace v1.22.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
@ -306,6 +304,8 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142
replace github.com/nektos/act => gitea.com/gitea/act v0.2.51
replace github.com/gorilla/feeds => github.com/yardenshoham/feeds v0.0.0-20240110072658-f3d0c21c0bd5
exclude github.com/gofrs/uuid v3.2.0+incompatible
exclude github.com/gofrs/uuid v4.0.0+incompatible

212
go.sum
View File

@ -39,8 +39,8 @@ code.gitea.io/actions-proto-go v0.3.1 h1:PMyiQtBKb8dNnpEO2R5rcZdXSis+UQZVo/SciMt
code.gitea.io/actions-proto-go v0.3.1/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI=
code.gitea.io/gitea-vet v0.2.3/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
code.gitea.io/sdk/gitea v0.17.0 h1:8JPBss4+Jf7AE1YcfyiGrngTXE8dFSG3si/bypsTH34=
code.gitea.io/sdk/gitea v0.17.0/go.mod h1:ndkDk99BnfiUCCYEUhpNzi0lpmApXlwRFqClBlOlEBg=
code.gitea.io/sdk/gitea v0.17.1 h1:3jCPOG2ojbl8AcfaUCRYLT5MUcBMFwS0OSK2mA5Zok8=
code.gitea.io/sdk/gitea v0.17.1/go.mod h1:aCnBqhHpoEWA180gMbaCtdX9Pl6BWBAuuP2miadoTNM=
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 h1:TXbikPqa7YRtfU9vS6QJBg77pUvbEb6StRdZO8t1bEY=
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsijsd8q1isWX8MACefDEgTQslQ4stk2AeeTt3kM=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
@ -76,10 +76,10 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/ClickHouse/ch-go v0.61.0 h1:22JYeFJoFNAU/Vod4etAeUEY28cYt7Ixnwqj1+EUfro=
github.com/ClickHouse/ch-go v0.61.0/go.mod h1:POJBl0MxEMS91Zd0uTgDDt05KfXEjf5KIwW6lNhje9Y=
github.com/ClickHouse/clickhouse-go/v2 v2.16.0 h1:rhMfnPewXPnY4Q4lQRGdYuTLRBRKJEIEYHtbUMrzmvI=
github.com/ClickHouse/clickhouse-go/v2 v2.16.0/go.mod h1:J7SPfIxwR+x4mQ+o8MLSe0oY50NNntEqCIjFe/T1VPM=
github.com/ClickHouse/ch-go v0.61.1 h1:j5rx3qnvcnYjhnP1IdXE/vdIRQiqgwAzyqOaasA6QCw=
github.com/ClickHouse/ch-go v0.61.1/go.mod h1:myxt/JZgy2BYHFGQqzmaIpbfr5CMbs3YHVULaWQj5YU=
github.com/ClickHouse/clickhouse-go/v2 v2.17.1 h1:ZCmAYWpu75IyEi7+Yrs/uaAjiCGY5wfW5kXo64exkX4=
github.com/ClickHouse/clickhouse-go/v2 v2.17.1/go.mod h1:rkGTvFDTLqLIm0ma+13xmcCfr/08Gvs7KmFt1tgiWHQ=
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
@ -96,16 +96,14 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX7IL/m9Y5LO+KQYv+t1CQOiFe6+SV2J7bE=
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I=
github.com/RoaringBitmap/roaring v1.7.0 h1:OZF303tJCER1Tj3x+aArx/S5X7hrT186ri6JjrGvG68=
github.com/RoaringBitmap/roaring v1.7.0/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
@ -118,8 +116,8 @@ github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3Uu
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
@ -136,18 +134,19 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.1.10/go.mod h1:w0XsmFg8qg6cmpTtJ0z3pKgjTDBMMnI/+I2syrE6XBE=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bits-and-blooms/bitset v1.12.0 h1:U/q1fAF7xXRhFCrhROzIfffYnu+dlS38vCZtmFVPHmA=
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/blevesearch/bleve/v2 v2.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM=
github.com/blevesearch/bleve/v2 v2.3.10 h1:z8V0wwGoL4rp7nG/O3qVVLYxUqCbEwskMt4iRJsPLgg=
github.com/blevesearch/bleve/v2 v2.3.10/go.mod h1:RJzeoeHC+vNHsoLR54+crS1HmOWpnH87fL70HAUCzIA=
github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
github.com/blevesearch/bleve_index_api v1.1.4 h1:n9Ilxlb80g9DAhchR95IcVrzohamDSri0wPnkKnva50=
github.com/blevesearch/bleve_index_api v1.1.4/go.mod h1:PbcwjIcRmjhGbkS/lJCpfgVSMROV6TRubGGAODaK1W8=
github.com/blevesearch/geo v0.1.18 h1:Np8jycHTZ5scFe7VEPLrDoHnnb9C4j636ue/CGrhtDw=
github.com/blevesearch/geo v0.1.18/go.mod h1:uRMGWG0HJYfWfFJpK3zTdnnr1K+ksZTuWKhXeSokfnM=
github.com/blevesearch/bleve_index_api v1.1.5 h1:0q05mzu6GT/kebzqKywCpou/eUea9wTKa7kfqX7QX+k=
github.com/blevesearch/bleve_index_api v1.1.5/go.mod h1:PbcwjIcRmjhGbkS/lJCpfgVSMROV6TRubGGAODaK1W8=
github.com/blevesearch/geo v0.1.19 h1:hlX1YpBZ+X+xfjS8hEpmM/tdPUFbqBME3mdAWKHo2s0=
github.com/blevesearch/geo v0.1.19/go.mod h1:EPyr3iJCcESYa830PnkFhqzJkOP7/daHT/ocun43WRY=
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y=
@ -156,8 +155,8 @@ github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
github.com/blevesearch/scorch_segment_api/v2 v2.0.1/go.mod h1:lq7yK2jQy1yQjtjTfU931aVqz7pYxEudHaDwOt1tXfU=
github.com/blevesearch/scorch_segment_api/v2 v2.2.5 h1:5SsNQmR8v1bojtGQ1zFhZravcMg5rdiX8AVu6LwlVtc=
github.com/blevesearch/scorch_segment_api/v2 v2.2.5/go.mod h1:8N2ytOlBCdurlxDgbqsfeR1oTKRN0ZVIKdUUP1VFZNc=
github.com/blevesearch/scorch_segment_api/v2 v2.2.6 h1:rewrzgFaCEjjfWovAB9NubMAd4+aCLxD3RaQcPDaoNo=
github.com/blevesearch/scorch_segment_api/v2 v2.2.6/go.mod h1:0rv+k/OIjtYCT/g7Z45pCOVweFyta+0AdXO8keKfZxo=
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
@ -197,8 +196,8 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bufbuild/connect-go v1.10.0 h1:QAJ3G9A1OYQW2Jbk3DeoJbkCxuKArrvZgDt47mjdTbg=
github.com/bufbuild/connect-go v1.10.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8=
github.com/buildkite/terminal-to-html/v3 v3.10.0 h1:mW1PSgDdUvmQMHOfXEOJDPGfqGWaskJfnGzdaQuJvsE=
github.com/buildkite/terminal-to-html/v3 v3.10.0/go.mod h1:qtuRyYs6/Sw3FS9jUyVEaANHgHGqZsGqMknPLyau5cQ=
github.com/buildkite/terminal-to-html/v3 v3.10.1 h1:znT9eD26LQ59dDJJEpMCwkP4wEptEAPi74hsTBuHdEo=
github.com/buildkite/terminal-to-html/v3 v3.10.1/go.mod h1:qtuRyYs6/Sw3FS9jUyVEaANHgHGqZsGqMknPLyau5cQ=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc=
github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg=
@ -307,8 +306,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46 h1:fYiA820jw7wmAvdXrHwMItxjJkra7dT9y8yiXhtzb94=
github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46/go.mod h1:i/TCLcdiX9Up/vs+Rp8c3yMbqp2Y4Y7Nh9uzGFCa5pM=
github.com/gliderlabs/ssh v0.3.6 h1:ZzjlDa05TcFRICb3anf/dSPN3ewz1Zx6CMLPWgkm3b8=
github.com/gliderlabs/ssh v0.3.6/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 h1:j2TrkUG/NATGi/EQS+MvEoF79CxiRUmT16ErFroNcKI=
@ -321,8 +320,8 @@ github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
@ -342,37 +341,37 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY=
github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
github.com/go-openapi/analysis v0.21.5 h1:3tHfEBh6Ia8eKc4M7khOGjPOAlWKJ10d877Cr9teujI=
github.com/go-openapi/analysis v0.21.5/go.mod h1:25YcZosX9Lwz2wBsrFrrsL8bmjjXdlyP6zsr2AMy29M=
github.com/go-openapi/analysis v0.22.2 h1:ZBmNoP2h5omLKr/srIC9bfqrUGzT6g6gNv03HE9Vpj0=
github.com/go-openapi/analysis v0.22.2/go.mod h1:pDF4UbZsQTo/oNuRfAWWd4dAh4yuYf//LYorPTjrpvo=
github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY=
github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho=
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-openapi/jsonpointer v0.20.1 h1:MkK4VEIEZMj4wT9PmjaUmGflVBr9nvud4Q4UVFbDoBE=
github.com/go-openapi/jsonpointer v0.20.1/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
github.com/go-openapi/jsonreference v0.20.3 h1:EjGcjTW8pD1mRis6+w/gmoBdqv5+RbE9B85D1NgDOVQ=
github.com/go-openapi/jsonreference v0.20.3/go.mod h1:FviDZ46i9ivh810gqzFLl5NttD5q3tSlMLqLr6okedM=
github.com/go-openapi/loads v0.21.3 h1:8sSH2FIm/SnbDUGv572md4YqVMFne/a9Eubvcd3anew=
github.com/go-openapi/loads v0.21.3/go.mod h1:Y3aMR24iHbKHppOj91nQ/SHc0cuPbAr4ndY4a02xydc=
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
github.com/go-openapi/loads v0.21.5 h1:jDzF4dSoHw6ZFADCGltDb2lE4F6De7aWSpe+IcsRzT0=
github.com/go-openapi/loads v0.21.5/go.mod h1:PxTsnFBoBe+z89riT+wYt3prmSBP6GDAQh2l9H1Flz8=
github.com/go-openapi/runtime v0.26.2 h1:elWyB9MacRzvIVgAZCBJmqTi7hBzU0hlKD4IvfX0Zl0=
github.com/go-openapi/runtime v0.26.2/go.mod h1:O034jyRZ557uJKzngbMDJXkcKJVzXJiymdSfgejrcRw=
github.com/go-openapi/spec v0.20.12 h1:cgSLbrsmziAP2iais+Vz7kSazwZ8rsUZd6TUzdDgkVI=
github.com/go-openapi/spec v0.20.12/go.mod h1:iSCgnBcwbMW9SfzJb8iYynXvcY6C/QFrI7otzF7xGM4=
github.com/go-openapi/strfmt v0.21.10 h1:JIsly3KXZB/Qf4UzvzJpg4OELH/0ASDQsyk//TTBDDk=
github.com/go-openapi/strfmt v0.21.10/go.mod h1:vNDMwbilnl7xKiO/Ve/8H8Bb2JIInBnH+lqiw6QWgis=
github.com/go-openapi/swag v0.22.5 h1:fVS63IE3M0lsuWRzuom3RLwUMVI2peDH01s6M70ugys=
github.com/go-openapi/swag v0.22.5/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
github.com/go-openapi/validate v0.22.4 h1:5v3jmMyIPKTR8Lv9syBAIRxG6lY0RqeBPB1LKEijzk8=
github.com/go-openapi/validate v0.22.4/go.mod h1:qm6O8ZIcPVdSY5219468Jv7kBdGvkiZLPOmqnqTUZ2A=
github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do=
github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI=
github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4=
github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8=
github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
github.com/go-openapi/validate v0.22.6 h1:+NhuwcEYpWdO5Nm4bmvhGLW0rt1Fcc532Mu3wpypXfo=
github.com/go-openapi/validate v0.22.6/go.mod h1:eaddXSqKeTg5XpSmj1dYyFTK/95n/XHwcOY+BMxKMyM=
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@ -387,10 +386,10 @@ github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-testfixtures/testfixtures/v3 v3.9.0 h1:938g5V+GWLVejm3Hc+nWCuEXRlcglZDDlN/t1gWzcSY=
github.com/go-testfixtures/testfixtures/v3 v3.9.0/go.mod h1:cdsKD2ApFBjdog9jRsz6EJqF+LClq/hrwE9K/1Dzo4s=
github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g=
github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw=
github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0=
github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY=
github.com/go-webauthn/webauthn v0.10.0 h1:yuW2e1tXnRAwAvKrR4q4LQmc6XtCMH639/ypZGhZCwk=
github.com/go-webauthn/webauthn v0.10.0/go.mod h1:l0NiauXhL6usIKqNLCUM3Qir43GK7ORg8ggold0Uv/Y=
github.com/go-webauthn/x v0.1.6 h1:QNAX+AWeqRt9loE8mULeWJCqhVG5D/jvdmJ47fIWCkQ=
github.com/go-webauthn/x v0.1.6/go.mod h1:W8dFVZ79o4f+nY1eOUICy/uq5dhrRl7mxQkYhXTo0FA=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/goccy/go-json v0.9.5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@ -483,8 +482,8 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e h1:bwOy7hAFd0C91URzMIEBfr6BAz29yk7Qj0cy6S7DJlU=
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 h1:WzfWbQz/Ze8v6l++GGbGNFZnUShVpP/0xffCPLL+ax8=
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -501,8 +500,6 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw=
github.com/gorilla/feeds v1.1.2/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@ -637,8 +634,6 @@ github.com/markbates/going v1.0.3 h1:mY45T5TvW+Xz5A6jY7lf4+NLg9D8+iuStIHyR7M8qsE
github.com/markbates/going v1.0.3/go.mod h1:fQiT6v6yQar9UD6bd/D4Z5Afbk9J6BBVBtLiyY4gp2o=
github.com/markbates/goth v1.78.0 h1:7VEIFDycJp9deyVv3YraGBPdD0ZYQW93Y3Aw1eVP3BY=
github.com/markbates/goth v1.78.0/go.mod h1:X6xdNgpapSENS0O35iTBBcMHoJDQDfI9bJl+APCkYMc=
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@ -650,18 +645,16 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI=
github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/meilisearch/meilisearch-go v0.26.0 h1:6IdFC9S53gEp7FMkt99swIFyEZE+4TwJAgen3eQdw40=
github.com/meilisearch/meilisearch-go v0.26.0/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0=
github.com/meilisearch/meilisearch-go v0.26.1 h1:3bmo2uLijX7kvBmiZ9LupVfC95TFcRJDgrRTzbOoE4A=
github.com/meilisearch/meilisearch-go v0.26.1/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0=
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.66 h1:bnTOXOHjOqv/gcMuiVbN9o2ngRItvqE774dG9nq0Dzw=
@ -723,10 +716,10 @@ github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s=
github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU=
github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/paulmach/orb v0.11.0 h1:JfVXJUBeH9ifc/OrhBY0lL16QsmPgpCHMlqSSYhcgAA=
github.com/paulmach/orb v0.11.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
@ -734,8 +727,8 @@ github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOS
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.19 h1:tYLzDnjDXh9qIxSTKHwXwOYmm9d887Y7Y1ZkyXYHAN4=
github.com/pierrec/lz4/v4 v4.1.19/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
@ -747,20 +740,20 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw=
github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0=
github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rhysd/actionlint v1.6.26 h1:zi7jPZf3Ks14gCXYAAL47uBziyFlX7+Xwilqhexct9g=
@ -788,8 +781,8 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
github.com/sassoftware/go-rpmutils v0.2.0 h1:pKW0HDYMFWQ5b4JQPiI3WI12hGsVoW0V8+GMoZiI/JE=
github.com/sassoftware/go-rpmutils v0.2.0/go.mod h1:TJJQYtLe/BeEmEjelI3b7xNZjzAukEkeWKmoakvaOoI=
github.com/sassoftware/go-rpmutils v0.2.1-0.20240124161140-277b154961dd h1:KpbqRPDwcAQTyaP+L+YudTRb3CnJlQ64Hfn1SF/zHBA=
github.com/sassoftware/go-rpmutils v0.2.1-0.20240124161140-277b154961dd/go.mod h1:TJJQYtLe/BeEmEjelI3b7xNZjzAukEkeWKmoakvaOoI=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
@ -870,8 +863,8 @@ github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
@ -883,8 +876,8 @@ github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7Fw
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xanzy/go-gitlab v0.95.2 h1:4p0IirHqEp5f0baK/aQqr4TR57IsD+8e4fuyAA1yi88=
github.com/xanzy/go-gitlab v0.95.2/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI=
github.com/xanzy/go-gitlab v0.96.0 h1:LGkZ+wSNMRtHIBaYE4Hq3dZVjprwHv3Y1+rhKU3WETs=
github.com/xanzy/go-gitlab v0.96.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
@ -904,6 +897,8 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMx
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yardenshoham/feeds v0.0.0-20240110072658-f3d0c21c0bd5 h1:3seWKGVhGoc66Ht5QlhQsr4xT2caDnFegsnh2NqvENU=
github.com/yardenshoham/feeds v0.0.0-20240110072658-f3d0c21c0bd5/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js=
github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
@ -937,10 +932,10 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y=
go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI=
go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0=
go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
@ -962,15 +957,14 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -981,12 +975,12 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4=
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -1052,16 +1046,16 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1074,8 +1068,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1134,8 +1128,9 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -1145,8 +1140,9 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1218,8 +1214,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1281,8 +1277,8 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200929141702-51c3e5b607fe/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -1297,8 +1293,8 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k=
google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -1312,8 +1308,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -1380,5 +1376,5 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.3.7-0.20240101024435-4992cba040fe h1:c+IGxoesJV3s4QZb55feZIb1sqFEUluAYHpe5uJIO6U=
xorm.io/xorm v1.3.7-0.20240101024435-4992cba040fe/go.mod h1:/PjYRKEcJ67WtOnb6DXEMb2Y0uWFaZSoDlhJUebWbXw=
xorm.io/xorm v1.3.7 h1:mLceAGu0b87r9pD4qXyxGHxifOXIIrAdVcA6k95/osw=
xorm.io/xorm v1.3.7/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw=

View File

@ -46,10 +46,13 @@ type ActionRun struct {
TriggerEvent string // the trigger event defined in the `on` configuration of the triggered workflow
Status Status `xorm:"index"`
Version int `xorm:"version default 0"` // Status could be updated concomitantly, so an optimistic lock is needed
Started timeutil.TimeStamp
Stopped timeutil.TimeStamp
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`
// Started and Stopped is used for recording last run time, if rerun happened, they will be reset to 0
Started timeutil.TimeStamp
Stopped timeutil.TimeStamp
// PreviousDuration is used for recording previous duration
PreviousDuration time.Duration
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`
}
func init() {
@ -118,7 +121,7 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error {
}
func (run *ActionRun) Duration() time.Duration {
return calculateDuration(run.Started, run.Stopped, run.Status)
return calculateDuration(run.Started, run.Stopped, run.Status) + run.PreviousDuration
}
func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {

View File

@ -446,12 +446,9 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
return nil, 0, err
}
sess := db.GetEngine(ctx).Where(cond)
if setting.Database.Type.IsMySQL() {
sess = sess.IndexHint("USE", "JOIN", "IDX_action_c_u_d")
}
sess = sess.Select("`action`.*"). // this line will avoid select other joined table's columns
Join("INNER", "repository", "`repository`.id = `action`.repo_id")
sess := db.GetEngine(ctx).Where(cond).
Select("`action`.*"). // this line will avoid select other joined table's columns
Join("INNER", "repository", "`repository`.id = `action`.repo_id")
opts.SetDefaultValues()
sess = db.SetSessionPagination(sess, &opts)

View File

@ -14,6 +14,7 @@ import (
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/gitrepo"
"xorm.io/xorm"
)
@ -65,7 +66,7 @@ func GetActivityStats(ctx context.Context, repo *repo_model.Repository, timeFrom
return nil, fmt.Errorf("FillUnresolvedIssues: %w", err)
}
if code {
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.RepoPath())
gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo)
if err != nil {
return nil, fmt.Errorf("OpenRepository: %w", err)
}
@ -82,7 +83,7 @@ func GetActivityStats(ctx context.Context, repo *repo_model.Repository, timeFrom
// GetActivityStatsTopAuthors returns top author stats for git commits for all branches
func GetActivityStatsTopAuthors(ctx context.Context, repo *repo_model.Repository, timeFrom time.Time, count int) ([]*ActivityAuthorData, error) {
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.RepoPath())
gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo)
if err != nil {
return nil, fmt.Errorf("OpenRepository: %w", err)
}

View File

@ -63,7 +63,6 @@ func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature st
}
if signer == nil {
signer, err = hashAndVerifyWithSubKeys(sig, token+"\n", key)
if err != nil {
return "", ErrGPGInvalidTokenSignature{
ID: key.KeyID,

View File

@ -54,6 +54,11 @@ func DeleteAuthTokenByID(ctx context.Context, id string) error {
return err
}
func DeleteAuthTokensByUserID(ctx context.Context, uid int64) error {
_, err := db.GetEngine(ctx).Where(builder.Eq{"user_id": uid}).Delete(&AuthToken{})
return err
}
func DeleteExpiredAuthTokens(ctx context.Context) error {
_, err := db.GetEngine(ctx).Where(builder.Lt{"expires_unix": timeutil.TimeStampNow()}).Delete(&AuthToken{})
return err

View File

@ -133,17 +133,21 @@ type FindOptionsOrder interface {
// Find represents a common find function which accept an options interface
func Find[T any](ctx context.Context, opts FindOptions) ([]*T, error) {
sess := GetEngine(ctx)
sess := GetEngine(ctx).Where(opts.ToConds())
if joinOpt, ok := opts.(FindOptionsJoin); ok && len(joinOpt.ToJoins()) > 0 {
if joinOpt, ok := opts.(FindOptionsJoin); ok {
for _, joinFunc := range joinOpt.ToJoins() {
if err := joinFunc(sess); err != nil {
return nil, err
}
}
}
if orderOpt, ok := opts.(FindOptionsOrder); ok {
if order := orderOpt.ToOrders(); order != "" {
sess.OrderBy(order)
}
}
sess = sess.Where(opts.ToConds())
page, pageSize := opts.GetPage(), opts.GetPageSize()
if !opts.IsListAll() && pageSize > 0 {
if page == 0 {
@ -151,9 +155,6 @@ func Find[T any](ctx context.Context, opts FindOptions) ([]*T, error) {
}
sess.Limit(pageSize, (page-1)*pageSize)
}
if newOpt, ok := opts.(FindOptionsOrder); ok && newOpt.ToOrders() != "" {
sess.OrderBy(newOpt.ToOrders())
}
findPageSize := defaultFindSliceSize
if pageSize > 0 {
@ -168,8 +169,8 @@ func Find[T any](ctx context.Context, opts FindOptions) ([]*T, error) {
// Count represents a common count function which accept an options interface
func Count[T any](ctx context.Context, opts FindOptions) (int64, error) {
sess := GetEngine(ctx)
if joinOpt, ok := opts.(FindOptionsJoin); ok && len(joinOpt.ToJoins()) > 0 {
sess := GetEngine(ctx).Where(opts.ToConds())
if joinOpt, ok := opts.(FindOptionsJoin); ok {
for _, joinFunc := range joinOpt.ToJoins() {
if err := joinFunc(sess); err != nil {
return 0, err
@ -178,7 +179,7 @@ func Count[T any](ctx context.Context, opts FindOptions) (int64, error) {
}
var object T
return sess.Where(opts.ToConds()).Count(&object)
return sess.Count(&object)
}
// FindAndCount represents a common findandcount function which accept an options interface
@ -188,8 +189,17 @@ func FindAndCount[T any](ctx context.Context, opts FindOptions) ([]*T, int64, er
if !opts.IsListAll() && pageSize > 0 && page >= 1 {
sess.Limit(pageSize, (page-1)*pageSize)
}
if newOpt, ok := opts.(FindOptionsOrder); ok && newOpt.ToOrders() != "" {
sess.OrderBy(newOpt.ToOrders())
if joinOpt, ok := opts.(FindOptionsJoin); ok {
for _, joinFunc := range joinOpt.ToJoins() {
if err := joinFunc(sess); err != nil {
return nil, 0, err
}
}
}
if orderOpt, ok := opts.(FindOptionsOrder); ok {
if order := orderOpt.ToOrders(); order != "" {
sess.OrderBy(order)
}
}
findPageSize := defaultFindSliceSize

View File

@ -285,3 +285,11 @@
lower_email: abcde@gitea.com
is_activated: true
is_primary: false
-
id: 37
uid: 37
email: user37@example.com
lower_email: user37@example.com
is_activated: true
is_primary: true

View File

@ -1095,7 +1095,7 @@
allow_git_hook: false
allow_import_local: false
allow_create_organization: true
prohibit_login: true
prohibit_login: false
avatar: avatar29
avatar_email: user30@example.com
use_custom_avatar: false
@ -1332,3 +1332,40 @@
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
-
id: 37
lower_name: user37
name: user37
full_name: User 37
email: user37@example.com
keep_email_private: false
email_notifications_preference: enabled
passwd: ZogKvWdyEx:password
passwd_hash_algo: dummy
must_change_password: false
login_source: 0
login_name: user37
type: 0
salt: ZogKvWdyEx
max_repo_creation: -1
is_active: true
is_admin: false
is_restricted: false
allow_git_hook: false
allow_import_local: false
allow_create_organization: true
prohibit_login: true
avatar: avatar29
avatar_email: user37@example.com
use_custom_avatar: false
num_followers: 0
num_following: 0
num_stars: 0
num_repos: 0
num_teams: 0
num_members: 0
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false

View File

@ -37,7 +37,7 @@ type CommitStatus struct {
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"`
TargetURL string `xorm:"TEXT"`
Description string `xorm:"TEXT"`
ContextHash string `xorm:"char(40) index"`
ContextHash string `xorm:"VARCHAR(64) index"`
Context string `xorm:"TEXT"`
Creator *user_model.User `xorm:"-"`
CreatorID int64

View File

@ -18,7 +18,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/references"
@ -271,7 +271,7 @@ type Comment struct {
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
// Reference issue in commit message
CommitSHA string `xorm:"VARCHAR(40)"`
CommitSHA string `xorm:"VARCHAR(64)"`
Attachments []*repo_model.Attachment `xorm:"-"`
Reactions ReactionList `xorm:"-"`
@ -763,8 +763,7 @@ func (c *Comment) LoadPushCommits(ctx context.Context) (err error) {
c.OldCommit = data.CommitIDs[0]
c.NewCommit = data.CommitIDs[1]
} else {
repoPath := c.Issue.Repo.RepoPath()
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoPath)
gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, c.Issue.Repo)
if err != nil {
return err
}

View File

@ -19,6 +19,7 @@ import (
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/gitrepo"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
@ -171,11 +172,11 @@ type PullRequest struct {
HeadBranch string
HeadCommitID string `xorm:"-"`
BaseBranch string
MergeBase string `xorm:"VARCHAR(40)"`
MergeBase string `xorm:"VARCHAR(64)"`
AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"`
HasMerged bool `xorm:"INDEX"`
MergedCommitID string `xorm:"VARCHAR(40)"`
MergedCommitID string `xorm:"VARCHAR(64)"`
MergerID int64 `xorm:"INDEX"`
Merger *user_model.User `xorm:"-"`
MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"`
@ -865,7 +866,7 @@ func PullRequestCodeOwnersReview(ctx context.Context, pull *Issue, pr *PullReque
return err
}
repo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
repo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo)
if err != nil {
return err
}

View File

@ -117,7 +117,7 @@ type Review struct {
Content string `xorm:"TEXT"`
// Official is a review made by an assigned approver (counts towards approval)
Official bool `xorm:"NOT NULL DEFAULT false"`
CommitID string `xorm:"VARCHAR(40)"`
CommitID string `xorm:"VARCHAR(64)"`
Stale bool `xorm:"NOT NULL DEFAULT false"`
Dismissed bool `xorm:"NOT NULL DEFAULT false"`

View File

@ -0,0 +1,11 @@
# type Repository struct {
# ID int64 `xorm:"pk autoincr"`
# }
-
id: 1
-
id: 2
-
id: 3
-
id: 10

View File

@ -554,6 +554,10 @@ var migrations = []Migration{
NewMigration("Add combined Index to issue_user.uid and issue_id", v1_22.AddCombinedIndexToIssueUser),
// v284 -> v285
NewMigration("Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable),
// v285 -> v286
NewMigration("Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun),
// v286 -> v287
NewMigration("Add support for SHA256 git repositories", v1_22.AdjustDBForSha256),
}
// GetCurrentDBVersion returns the current db version

View File

@ -0,0 +1,18 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_22 //nolint
import (
"time"
"xorm.io/xorm"
)
func AddPreviousDurationToActionRun(x *xorm.Engine) error {
type ActionRun struct {
PreviousDuration time.Duration
}
return x.Sync(&ActionRun{})
}

View File

@ -0,0 +1,104 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_22 //nolint
import (
"errors"
"fmt"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"xorm.io/xorm"
)
func expandHashReferencesToSha256(x *xorm.Engine) error {
alteredTables := [][2]string{
{"commit_status", "context_hash"},
{"comment", "commit_sha"},
{"pull_request", "merge_base"},
{"pull_request", "merged_commit_id"},
{"review", "commit_id"},
{"review_state", "commit_sha"},
{"repo_archiver", "commit_id"},
{"release", "sha1"},
{"repo_indexer_status", "commit_sha"},
}
db := x.NewSession()
defer db.Close()
if err := db.Begin(); err != nil {
return err
}
if !setting.Database.Type.IsSQLite3() {
if setting.Database.Type.IsMSSQL() {
// drop indexes that need to be re-created afterwards
droppedIndexes := []string{
"DROP INDEX commit_status.IDX_commit_status_context_hash",
"DROP INDEX review_state.UQE_review_state_pull_commit_user",
"DROP INDEX repo_archiver.UQE_repo_archiver_s",
}
for _, s := range droppedIndexes {
_, err := db.Exec(s)
if err != nil {
return errors.New(s + " " + err.Error())
}
}
}
for _, alts := range alteredTables {
var err error
if setting.Database.Type.IsMySQL() {
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` MODIFY COLUMN `%s` VARCHAR(64)", alts[0], alts[1]))
} else if setting.Database.Type.IsMSSQL() {
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` VARCHAR(64)", alts[0], alts[1]))
} else {
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` TYPE VARCHAR(64)", alts[0], alts[1]))
}
if err != nil {
return fmt.Errorf("alter column '%s' of table '%s' failed: %w", alts[1], alts[0], err)
}
}
if setting.Database.Type.IsMSSQL() {
recreateIndexes := []string{
"CREATE INDEX IDX_commit_status_context_hash ON commit_status(context_hash)",
"CREATE UNIQUE INDEX UQE_review_state_pull_commit_user ON review_state(user_id, pull_id, commit_sha)",
"CREATE UNIQUE INDEX UQE_repo_archiver_s ON repo_archiver(repo_id, type, commit_id)",
}
for _, s := range recreateIndexes {
_, err := db.Exec(s)
if err != nil {
return errors.New(s + " " + err.Error())
}
}
}
}
log.Debug("Updated database tables to hold SHA256 git hash references")
return db.Commit()
}
func addObjectFormatNameToRepository(x *xorm.Engine) error {
type Repository struct {
ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"`
}
if err := x.Sync(new(Repository)); err != nil {
return err
}
// Here to catch weird edge-cases where column constraints above are
// not applied by the DB backend
_, err := x.Exec("UPDATE repository set object_format_name = 'sha1' WHERE object_format_name = '' or object_format_name IS NULL")
return err
}
func AdjustDBForSha256(x *xorm.Engine) error {
if err := expandHashReferencesToSha256(x); err != nil {
return err
}
return addObjectFormatNameToRepository(x)
}

View File

@ -0,0 +1,62 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_22 //nolint
import (
"testing"
"code.gitea.io/gitea/models/migrations/base"
"github.com/stretchr/testify/assert"
"xorm.io/xorm"
)
func PrepareOldRepository(t *testing.T) (*xorm.Engine, func()) {
type Repository struct { // old struct
ID int64 `xorm:"pk autoincr"`
}
// Prepare and load the testing database
return base.PrepareTestEnv(t, 0, new(Repository))
}
func Test_RepositoryFormat(t *testing.T) {
x, deferable := PrepareOldRepository(t)
defer deferable()
type Repository struct {
ID int64 `xorm:"pk autoincr"`
ObjectFormatName string `xorg:"not null default('sha1')"`
}
repo := new(Repository)
// check we have some records to migrate
count, err := x.Count(new(Repository))
assert.NoError(t, err)
assert.EqualValues(t, 4, count)
assert.NoError(t, AdjustDBForSha256(x))
repo.ID = 20
repo.ObjectFormatName = "sha256"
_, err = x.Insert(repo)
assert.NoError(t, err)
count, err = x.Count(new(Repository))
assert.NoError(t, err)
assert.EqualValues(t, 5, count)
repo = new(Repository)
ok, err := x.ID(2).Get(repo)
assert.NoError(t, err)
assert.EqualValues(t, true, ok)
assert.EqualValues(t, "sha1", repo.ObjectFormatName)
repo = new(Repository)
ok, err = x.ID(20).Get(repo)
assert.NoError(t, err)
assert.EqualValues(t, true, ok)
assert.EqualValues(t, "sha256", repo.ObjectFormatName)
}

View File

@ -191,18 +191,18 @@ type Package struct {
func TryInsertPackage(ctx context.Context, p *Package) (*Package, error) {
e := db.GetEngine(ctx)
key := &Package{
OwnerID: p.OwnerID,
Type: p.Type,
LowerName: p.LowerName,
}
existing := &Package{}
has, err := e.Get(key)
has, err := e.Where(builder.Eq{
"owner_id": p.OwnerID,
"type": p.Type,
"lower_name": p.LowerName,
}).Get(existing)
if err != nil {
return nil, err
}
if has {
return key, ErrDuplicatePackage
return existing, ErrDuplicatePackage
}
if _, err = e.Insert(p); err != nil {
return nil, err

View File

@ -41,12 +41,20 @@ type PackageBlob struct {
func GetOrInsertBlob(ctx context.Context, pb *PackageBlob) (*PackageBlob, bool, error) {
e := db.GetEngine(ctx)
has, err := e.Get(pb)
existing := &PackageBlob{}
has, err := e.Where(builder.Eq{
"size": pb.Size,
"hash_md5": pb.HashMD5,
"hash_sha1": pb.HashSHA1,
"hash_sha256": pb.HashSHA256,
"hash_sha512": pb.HashSHA512,
}).Get(existing)
if err != nil {
return nil, false, err
}
if has {
return pb, true, nil
return existing, true, nil
}
if _, err = e.Insert(pb); err != nil {
return nil, false, err

View File

@ -46,18 +46,18 @@ type PackageFile struct {
func TryInsertFile(ctx context.Context, pf *PackageFile) (*PackageFile, error) {
e := db.GetEngine(ctx)
key := &PackageFile{
VersionID: pf.VersionID,
LowerName: pf.LowerName,
CompositeKey: pf.CompositeKey,
}
existing := &PackageFile{}
has, err := e.Get(key)
has, err := e.Where(builder.Eq{
"version_id": pf.VersionID,
"lower_name": pf.LowerName,
"composite_key": pf.CompositeKey,
}).Get(existing)
if err != nil {
return nil, err
}
if has {
return pf, ErrDuplicatePackageFile
return existing, ErrDuplicatePackageFile
}
if _, err = e.Insert(pf); err != nil {
return nil, err
@ -93,13 +93,13 @@ func GetFileForVersionByName(ctx context.Context, versionID int64, name, key str
return nil, ErrPackageFileNotExist
}
pf := &PackageFile{
VersionID: versionID,
LowerName: strings.ToLower(name),
CompositeKey: key,
}
pf := &PackageFile{}
has, err := db.GetEngine(ctx).Get(pf)
has, err := db.GetEngine(ctx).Where(builder.Eq{
"version_id": versionID,
"lower_name": strings.ToLower(name),
"composite_key": key,
}).Get(pf)
if err != nil {
return nil, err
}

View File

@ -39,17 +39,17 @@ type PackageVersion struct {
func GetOrInsertVersion(ctx context.Context, pv *PackageVersion) (*PackageVersion, error) {
e := db.GetEngine(ctx)
key := &PackageVersion{
PackageID: pv.PackageID,
LowerVersion: pv.LowerVersion,
}
existing := &PackageVersion{}
has, err := e.Get(key)
has, err := e.Where(builder.Eq{
"package_id": pv.PackageID,
"lower_version": pv.LowerVersion,
}).Get(existing)
if err != nil {
return nil, err
}
if has {
return key, ErrDuplicatePackageVersion
return existing, ErrDuplicatePackageVersion
}
if _, err = e.Insert(pv); err != nil {
return nil, err

View File

@ -0,0 +1,23 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package rpm
import (
"context"
packages_model "code.gitea.io/gitea/models/packages"
rpm_module "code.gitea.io/gitea/modules/packages/rpm"
)
// GetGroups gets all available groups
func GetGroups(ctx context.Context, ownerID int64) ([]string, error) {
return packages_model.GetDistinctPropertyValues(
ctx,
packages_model.TypeRpm,
ownerID,
packages_model.PropertyTypeFile,
rpm_module.PropertyGroup,
nil,
)
}

View File

@ -39,7 +39,7 @@ type ReviewState struct {
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"`
PullID int64 `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"` // Which PR was the review on?
CommitSHA string `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"` // Which commit was the head commit for the review?
CommitSHA string `xorm:"NOT NULL VARCHAR(64) UNIQUE(pull_commit_user)"` // Which commit was the head commit for the review?
UpdatedFiles map[string]ViewedState `xorm:"NOT NULL LONGTEXT JSON"` // Stores for each of the changed files of a PR whether they have been viewed, changed since last viewed, or not viewed
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` // Is an accurate indicator of the order of commits as we do not expect it to be possible to make reviews on previous commits
}

View File

@ -33,7 +33,7 @@ type RepoArchiver struct { //revive:disable-line:exported
RepoID int64 `xorm:"index unique(s)"`
Type git.ArchiveType `xorm:"unique(s)"`
Status ArchiverStatus
CommitID string `xorm:"VARCHAR(40) unique(s)"`
CommitID string `xorm:"VARCHAR(64) unique(s)"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
}

View File

@ -121,8 +121,11 @@ func GetPushMirrorsSyncedOnCommit(ctx context.Context, repoID int64) ([]*PushMir
// PushMirrorsIterate iterates all push-mirror repositories.
func PushMirrorsIterate(ctx context.Context, limit int, f func(idx int, bean any) error) error {
sess := db.GetEngine(ctx).
Where("last_update + (`interval` / ?) <= ?", time.Second, time.Now().Unix()).
And("`interval` != 0").
Table("push_mirror").
Join("INNER", "`repository`", "`repository`.id = `push_mirror`.repo_id").
Where("`push_mirror`.last_update + (`push_mirror`.`interval` / ?) <= ?", time.Second, time.Now().Unix()).
And("`push_mirror`.`interval` != 0").
And("`repository`.is_archived = ?", false).
OrderBy("last_update ASC")
if limit > 0 {
sess = sess.Limit(limit)

View File

@ -76,7 +76,7 @@ type Release struct {
Target string
TargetBehind string `xorm:"-"` // to handle non-existing or empty target
Title string
Sha1 string `xorm:"VARCHAR(40)"`
Sha1 string `xorm:"VARCHAR(64)"`
NumCommits int64
NumCommitsBehind int64 `xorm:"-"`
Note string `xorm:"TEXT"`

View File

@ -180,7 +180,7 @@ type Repository struct {
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
Topics []string `xorm:"TEXT JSON"`
ObjectFormatName string `xorm:"-"`
ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"`
TrustModel TrustModelType
@ -196,6 +196,14 @@ func init() {
db.RegisterModel(new(Repository))
}
func (repo *Repository) GetName() string {
return repo.Name
}
func (repo *Repository) GetOwnerName() string {
return repo.OwnerName
}
// SanitizedOriginalURL returns a sanitized OriginalURL
func (repo *Repository) SanitizedOriginalURL() string {
if repo.OriginalURL == "" {
@ -276,10 +284,6 @@ func (repo *Repository) AfterLoad() {
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns
// this is a temporary behaviour to support old repos, next step is to store the object format in the database
// and read from database so this line could be removed. To not depend on git module, we use a constant variable here
repo.ObjectFormatName = "sha1"
}
// LoadAttributes loads attributes of the repository.

View File

@ -27,7 +27,7 @@ const (
type RepoIndexerStatus struct { //revive:disable-line:exported
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX(s)"`
CommitSha string `xorm:"VARCHAR(40)"`
CommitSha string `xorm:"VARCHAR(64)"`
IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"`
}

View File

@ -394,7 +394,7 @@ func syncTopicsInRepository(sess db.Engine, repoID int64) error {
topicNames := make([]string, 0, 25)
if err := sess.Table("topic").Cols("name").
Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id").
Where("repo_topic.repo_id = ?", repoID).Desc("topic.repo_count").Find(&topicNames); err != nil {
Where("repo_topic.repo_id = ?", repoID).Asc("topic.name").Find(&topicNames); err != nil {
return err
}

View File

@ -6,7 +6,6 @@ package repo
import (
"context"
"fmt"
"strings"
"time"
"code.gitea.io/gitea/models/db"
@ -135,55 +134,6 @@ func CheckCreateRepository(ctx context.Context, doer, u *user_model.User, name s
return nil
}
// ChangeRepositoryName changes all corresponding setting from old repository name to new one.
func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *Repository, newRepoName string) (err error) {
oldRepoName := repo.Name
newRepoName = strings.ToLower(newRepoName)
if err = IsUsableRepoName(newRepoName); err != nil {
return err
}
if err := repo.LoadOwner(ctx); err != nil {
return err
}
has, err := IsRepositoryModelOrDirExist(ctx, repo.Owner, newRepoName)
if err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName}
}
newRepoPath := RepoPath(repo.Owner.Name, newRepoName)
if err = util.Rename(repo.RepoPath(), newRepoPath); err != nil {
return fmt.Errorf("rename repository directory: %w", err)
}
wikiPath := repo.WikiPath()
isExist, err := util.IsExist(wikiPath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", wikiPath, err)
return err
}
if isExist {
if err = util.Rename(wikiPath, WikiPath(repo.Owner.Name, newRepoName)); err != nil {
return fmt.Errorf("rename repository wiki: %w", err)
}
}
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
if err := NewRedirect(ctx, repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil {
return err
}
return committer.Commit()
}
// UpdateRepoSize updates the repository size, calculating it using getDirectorySize
func UpdateRepoSize(ctx context.Context, repoID, gitSize, lfsSize int64) error {
_, err := db.GetEngine(ctx).ID(repoID).Cols("size", "git_size", "lfs_size").NoAutoTime().Update(&Repository{

View File

@ -6,17 +6,13 @@ package models
import (
"context"
"fmt"
"os"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
)
// RepoTransfer is used to manage repository transfers
@ -115,32 +111,11 @@ func GetPendingRepositoryTransfer(ctx context.Context, repo *repo_model.Reposito
return transfer, nil
}
func deleteRepositoryTransfer(ctx context.Context, repoID int64) error {
func DeleteRepositoryTransfer(ctx context.Context, repoID int64) error {
_, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Delete(&RepoTransfer{})
return err
}
// CancelRepositoryTransfer marks the repository as ready and remove pending transfer entry,
// thus cancel the transfer process.
func CancelRepositoryTransfer(ctx context.Context, repo *repo_model.Repository) error {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
repo.Status = repo_model.RepositoryReady
if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
return err
}
if err := deleteRepositoryTransfer(ctx, repo.ID); err != nil {
return err
}
return committer.Commit()
}
// TestRepositoryReadyForTransfer make sure repo is ready to transfer
func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
switch status {
@ -197,223 +172,3 @@ func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_m
return db.Insert(ctx, transfer)
})
}
// TransferOwnership transfers all corresponding repository items from old user to new one.
func TransferOwnership(ctx context.Context, doer *user_model.User, newOwnerName string, repo *repo_model.Repository) (err error) {
repoRenamed := false
wikiRenamed := false
oldOwnerName := doer.Name
defer func() {
if !repoRenamed && !wikiRenamed {
return
}
recoverErr := recover()
if err == nil && recoverErr == nil {
return
}
if repoRenamed {
if err := util.Rename(repo_model.RepoPath(newOwnerName, repo.Name), repo_model.RepoPath(oldOwnerName, repo.Name)); err != nil {
log.Critical("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name,
repo_model.RepoPath(newOwnerName, repo.Name), repo_model.RepoPath(oldOwnerName, repo.Name), err)
}
}
if wikiRenamed {
if err := util.Rename(repo_model.WikiPath(newOwnerName, repo.Name), repo_model.WikiPath(oldOwnerName, repo.Name)); err != nil {
log.Critical("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name,
repo_model.WikiPath(newOwnerName, repo.Name), repo_model.WikiPath(oldOwnerName, repo.Name), err)
}
}
if recoverErr != nil {
log.Error("Panic within TransferOwnership: %v\n%s", recoverErr, log.Stack(2))
panic(recoverErr)
}
}()
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
sess := db.GetEngine(ctx)
newOwner, err := user_model.GetUserByName(ctx, newOwnerName)
if err != nil {
return fmt.Errorf("get new owner '%s': %w", newOwnerName, err)
}
newOwnerName = newOwner.Name // ensure capitalisation matches
// Check if new owner has repository with same name.
if has, err := repo_model.IsRepositoryModelOrDirExist(ctx, newOwner, repo.Name); err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
return repo_model.ErrRepoAlreadyExist{
Uname: newOwnerName,
Name: repo.Name,
}
}
oldOwner := repo.Owner
oldOwnerName = oldOwner.Name
// Note: we have to set value here to make sure recalculate accesses is based on
// new owner.
repo.OwnerID = newOwner.ID
repo.Owner = newOwner
repo.OwnerName = newOwner.Name
// Update repository.
if _, err := sess.ID(repo.ID).Update(repo); err != nil {
return fmt.Errorf("update owner: %w", err)
}
// Remove redundant collaborators.
collaborators, err := repo_model.GetCollaborators(ctx, repo.ID, db.ListOptions{})
if err != nil {
return fmt.Errorf("getCollaborators: %w", err)
}
// Dummy object.
collaboration := &repo_model.Collaboration{RepoID: repo.ID}
for _, c := range collaborators {
if c.IsGhost() {
collaboration.ID = c.Collaboration.ID
if _, err := sess.Delete(collaboration); err != nil {
return fmt.Errorf("remove collaborator '%d': %w", c.ID, err)
}
collaboration.ID = 0
}
if c.ID != newOwner.ID {
isMember, err := organization.IsOrganizationMember(ctx, newOwner.ID, c.ID)
if err != nil {
return fmt.Errorf("IsOrgMember: %w", err)
} else if !isMember {
continue
}
}
collaboration.UserID = c.ID
if _, err := sess.Delete(collaboration); err != nil {
return fmt.Errorf("remove collaborator '%d': %w", c.ID, err)
}
collaboration.UserID = 0
}
// Remove old team-repository relations.
if oldOwner.IsOrganization() {
if err := organization.RemoveOrgRepo(ctx, oldOwner.ID, repo.ID); err != nil {
return fmt.Errorf("removeOrgRepo: %w", err)
}
}
if newOwner.IsOrganization() {
teams, err := organization.FindOrgTeams(ctx, newOwner.ID)
if err != nil {
return fmt.Errorf("LoadTeams: %w", err)
}
for _, t := range teams {
if t.IncludesAllRepositories {
if err := AddRepository(ctx, t, repo); err != nil {
return fmt.Errorf("AddRepository: %w", err)
}
}
}
} else if err := access_model.RecalculateAccesses(ctx, repo); err != nil {
// Organization called this in addRepository method.
return fmt.Errorf("recalculateAccesses: %w", err)
}
// Update repository count.
if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.ID); err != nil {
return fmt.Errorf("increase new owner repository count: %w", err)
} else if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", oldOwner.ID); err != nil {
return fmt.Errorf("decrease old owner repository count: %w", err)
}
if err := repo_model.WatchRepo(ctx, doer.ID, repo.ID, true); err != nil {
return fmt.Errorf("watchRepo: %w", err)
}
// Remove watch for organization.
if oldOwner.IsOrganization() {
if err := repo_model.WatchRepo(ctx, oldOwner.ID, repo.ID, false); err != nil {
return fmt.Errorf("watchRepo [false]: %w", err)
}
}
// Delete labels that belong to the old organization and comments that added these labels
if oldOwner.IsOrganization() {
if _, err := sess.Exec(`DELETE FROM issue_label WHERE issue_label.id IN (
SELECT il_too.id FROM (
SELECT il_too_too.id
FROM issue_label AS il_too_too
INNER JOIN label ON il_too_too.label_id = label.id
INNER JOIN issue on issue.id = il_too_too.issue_id
WHERE
issue.repo_id = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != ?))
) AS il_too )`, repo.ID, newOwner.ID); err != nil {
return fmt.Errorf("Unable to remove old org labels: %w", err)
}
if _, err := sess.Exec(`DELETE FROM comment WHERE comment.id IN (
SELECT il_too.id FROM (
SELECT com.id
FROM comment AS com
INNER JOIN label ON com.label_id = label.id
INNER JOIN issue ON issue.id = com.issue_id
WHERE
com.type = ? AND issue.repo_id = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != ?))
) AS il_too)`, issues_model.CommentTypeLabel, repo.ID, newOwner.ID); err != nil {
return fmt.Errorf("Unable to remove old org label comments: %w", err)
}
}
// Rename remote repository to new path and delete local copy.
dir := user_model.UserPath(newOwner.Name)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("Failed to create dir %s: %w", dir, err)
}
if err := util.Rename(repo_model.RepoPath(oldOwner.Name, repo.Name), repo_model.RepoPath(newOwner.Name, repo.Name)); err != nil {
return fmt.Errorf("rename repository directory: %w", err)
}
repoRenamed = true
// Rename remote wiki repository to new path and delete local copy.
wikiPath := repo_model.WikiPath(oldOwner.Name, repo.Name)
if isExist, err := util.IsExist(wikiPath); err != nil {
log.Error("Unable to check if %s exists. Error: %v", wikiPath, err)
return err
} else if isExist {
if err := util.Rename(wikiPath, repo_model.WikiPath(newOwner.Name, repo.Name)); err != nil {
return fmt.Errorf("rename repository wiki: %w", err)
}
wikiRenamed = true
}
if err := deleteRepositoryTransfer(ctx, repo.ID); err != nil {
return fmt.Errorf("deleteRepositoryTransfer: %w", err)
}
repo.Status = repo_model.RepositoryReady
if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
return err
}
// If there was previously a redirect at this location, remove it.
if err := repo_model.DeleteRedirect(ctx, newOwner.ID, repo.Name); err != nil {
return fmt.Errorf("delete repo redirect: %w", err)
}
if err := repo_model.NewRedirect(ctx, oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
return fmt.Errorf("repo_model.NewRedirect: %w", err)
}
return committer.Commit()
}

View File

@ -1,57 +0,0 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
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"
"github.com/stretchr/testify/assert"
)
func TestRepositoryTransfer(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
transfer, err := GetPendingRepositoryTransfer(db.DefaultContext, repo)
assert.NoError(t, err)
assert.NotNil(t, transfer)
// Cancel transfer
assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, 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(db.DefaultContext, doer, user2, repo.ID, nil))
transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo)
assert.Nil(t, err)
assert.NoError(t, transfer.LoadAttributes(db.DefaultContext))
assert.Equal(t, "user2", transfer.Recipient.Name)
org6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
// Only transfer can be started at any given time
err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, org6, repo.ID, nil)
assert.Error(t, err)
assert.True(t, IsErrRepoTransferInProgress(err))
// Unknown user
err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil)
assert.Error(t, err)
// Cancel transfer
assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, repo))
}

View File

@ -142,12 +142,24 @@ func (email *EmailAddress) BeforeInsert() {
}
}
func InsertEmailAddress(ctx context.Context, email *EmailAddress) (*EmailAddress, error) {
if err := db.Insert(ctx, email); err != nil {
return nil, err
}
return email, nil
}
func UpdateEmailAddress(ctx context.Context, email *EmailAddress) error {
_, err := db.GetEngine(ctx).ID(email.ID).AllCols().Update(email)
return err
}
var emailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
// ValidateEmail check if email is a allowed address
func ValidateEmail(email string) error {
if len(email) == 0 {
return nil
return ErrEmailInvalid{email}
}
if !emailRegexp.MatchString(email) {
@ -177,6 +189,36 @@ func ValidateEmail(email string) error {
return nil
}
func GetEmailAddressByEmail(ctx context.Context, email string) (*EmailAddress, error) {
ea := &EmailAddress{}
if has, err := db.GetEngine(ctx).Where("lower_email=?", strings.ToLower(email)).Get(ea); err != nil {
return nil, err
} else if !has {
return nil, ErrEmailAddressNotExist{email}
}
return ea, nil
}
func GetEmailAddressOfUser(ctx context.Context, email string, uid int64) (*EmailAddress, error) {
ea := &EmailAddress{}
if has, err := db.GetEngine(ctx).Where("lower_email=? AND uid=?", strings.ToLower(email), uid).Get(ea); err != nil {
return nil, err
} else if !has {
return nil, ErrEmailAddressNotExist{email}
}
return ea, nil
}
func GetPrimaryEmailAddressOfUser(ctx context.Context, uid int64) (*EmailAddress, error) {
ea := &EmailAddress{}
if has, err := db.GetEngine(ctx).Where("uid=? AND is_primary=?", uid, true).Get(ea); err != nil {
return nil, err
} else if !has {
return nil, ErrEmailAddressNotExist{}
}
return ea, nil
}
// GetEmailAddresses returns all email addresses belongs to given user.
func GetEmailAddresses(ctx context.Context, uid int64) ([]*EmailAddress, error) {
emails := make([]*EmailAddress, 0, 5)
@ -235,91 +277,6 @@ func IsEmailUsed(ctx context.Context, email string) (bool, error) {
return db.GetEngine(ctx).Where("lower_email=?", strings.ToLower(email)).Get(&EmailAddress{})
}
// AddEmailAddress adds an email address to given user.
func AddEmailAddress(ctx context.Context, email *EmailAddress) error {
email.Email = strings.TrimSpace(email.Email)
used, err := IsEmailUsed(ctx, email.Email)
if err != nil {
return err
} else if used {
return ErrEmailAlreadyUsed{email.Email}
}
if err = ValidateEmail(email.Email); err != nil {
return err
}
return db.Insert(ctx, email)
}
// AddEmailAddresses adds an email address to given user.
func AddEmailAddresses(ctx context.Context, emails []*EmailAddress) error {
if len(emails) == 0 {
return nil
}
// Check if any of them has been used
for i := range emails {
emails[i].Email = strings.TrimSpace(emails[i].Email)
used, err := IsEmailUsed(ctx, emails[i].Email)
if err != nil {
return err
} else if used {
return ErrEmailAlreadyUsed{emails[i].Email}
}
if err = ValidateEmail(emails[i].Email); err != nil {
return err
}
}
if err := db.Insert(ctx, emails); err != nil {
return fmt.Errorf("Insert: %w", err)
}
return nil
}
// DeleteEmailAddress deletes an email address of given user.
func DeleteEmailAddress(ctx context.Context, email *EmailAddress) (err error) {
if email.IsPrimary {
return ErrPrimaryEmailCannotDelete{Email: email.Email}
}
var deleted int64
// ask to check UID
address := EmailAddress{
UID: email.UID,
}
if email.ID > 0 {
deleted, err = db.GetEngine(ctx).ID(email.ID).Delete(&address)
} else {
if email.Email != "" && email.LowerEmail == "" {
email.LowerEmail = strings.ToLower(email.Email)
}
deleted, err = db.GetEngine(ctx).
Where("lower_email=?", email.LowerEmail).
Delete(&address)
}
if err != nil {
return err
} else if deleted != 1 {
return ErrEmailAddressNotExist{Email: email.Email}
}
return nil
}
// DeleteEmailAddresses deletes multiple email addresses
func DeleteEmailAddresses(ctx context.Context, emails []*EmailAddress) (err error) {
for i := range emails {
if err = DeleteEmailAddress(ctx, emails[i]); err != nil {
return err
}
}
return nil
}
// DeleteInactiveEmailAddresses deletes inactive email addresses
func DeleteInactiveEmailAddresses(ctx context.Context) error {
_, err := db.GetEngine(ctx).

View File

@ -42,96 +42,6 @@ func TestIsEmailUsed(t *testing.T) {
assert.False(t, isExist)
}
func TestAddEmailAddress(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
assert.NoError(t, user_model.AddEmailAddress(db.DefaultContext, &user_model.EmailAddress{
Email: "user1234567890@example.com",
LowerEmail: "user1234567890@example.com",
IsPrimary: true,
IsActivated: true,
}))
// ErrEmailAlreadyUsed
err := user_model.AddEmailAddress(db.DefaultContext, &user_model.EmailAddress{
Email: "user1234567890@example.com",
LowerEmail: "user1234567890@example.com",
})
assert.Error(t, err)
assert.True(t, user_model.IsErrEmailAlreadyUsed(err))
}
func TestAddEmailAddresses(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
// insert multiple email address
emails := make([]*user_model.EmailAddress, 2)
emails[0] = &user_model.EmailAddress{
Email: "user1234@example.com",
LowerEmail: "user1234@example.com",
IsActivated: true,
}
emails[1] = &user_model.EmailAddress{
Email: "user5678@example.com",
LowerEmail: "user5678@example.com",
IsActivated: true,
}
assert.NoError(t, user_model.AddEmailAddresses(db.DefaultContext, emails))
// ErrEmailAlreadyUsed
err := user_model.AddEmailAddresses(db.DefaultContext, emails)
assert.Error(t, err)
assert.True(t, user_model.IsErrEmailAlreadyUsed(err))
}
func TestDeleteEmailAddress(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
assert.NoError(t, user_model.DeleteEmailAddress(db.DefaultContext, &user_model.EmailAddress{
UID: int64(1),
ID: int64(33),
Email: "user1-2@example.com",
LowerEmail: "user1-2@example.com",
}))
assert.NoError(t, user_model.DeleteEmailAddress(db.DefaultContext, &user_model.EmailAddress{
UID: int64(1),
Email: "user1-3@example.com",
LowerEmail: "user1-3@example.com",
}))
// Email address does not exist
err := user_model.DeleteEmailAddress(db.DefaultContext, &user_model.EmailAddress{
UID: int64(1),
Email: "user1234567890@example.com",
LowerEmail: "user1234567890@example.com",
})
assert.Error(t, err)
}
func TestDeleteEmailAddresses(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
// delete multiple email address
emails := make([]*user_model.EmailAddress, 2)
emails[0] = &user_model.EmailAddress{
UID: int64(2),
ID: int64(3),
Email: "user2@example.com",
LowerEmail: "user2@example.com",
}
emails[1] = &user_model.EmailAddress{
UID: int64(2),
Email: "user2-2@example.com",
LowerEmail: "user2-2@example.com",
}
assert.NoError(t, user_model.DeleteEmailAddresses(db.DefaultContext, emails))
// ErrEmailAlreadyUsed
err := user_model.DeleteEmailAddresses(db.DefaultContext, emails)
assert.Error(t, err)
}
func TestMakeEmailPrimary(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())

View File

@ -108,18 +108,3 @@ func IsErrUserIsNotLocal(err error) bool {
_, ok := err.(ErrUserIsNotLocal)
return ok
}
type ErrUsernameNotChanged struct {
UID int64
Name string
}
func (err ErrUsernameNotChanged) Error() string {
return fmt.Sprintf("username hasn't been changed[uid: %d, name: %s]", err.UID, err.Name)
}
// IsErrUsernameNotChanged
func IsErrUsernameNotChanged(err error) bool {
_, ok := err.(ErrUsernameNotChanged)
return ok
}

View File

@ -196,18 +196,6 @@ func (u *User) SetLastLogin() {
u.LastLoginUnix = timeutil.TimeStampNow()
}
// UpdateUserDiffViewStyle updates the users diff view style
func UpdateUserDiffViewStyle(ctx context.Context, u *User, style string) error {
u.DiffViewStyle = style
return UpdateUserCols(ctx, u, "diff_view_style")
}
// UpdateUserTheme updates a users' theme irrespective of the site wide theme
func UpdateUserTheme(ctx context.Context, u *User, themeName string) error {
u.Theme = themeName
return UpdateUserCols(ctx, u, "theme")
}
// GetPlaceholderEmail returns an noreply email
func (u *User) GetPlaceholderEmail() string {
return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
@ -378,13 +366,6 @@ func (u *User) NewGitSig() *git.Signature {
// SetPassword hashes a password using the algorithm defined in the config value of PASSWORD_HASH_ALGO
// change passwd, salt and passwd_hash_algo fields
func (u *User) SetPassword(passwd string) (err error) {
if len(passwd) == 0 {
u.Passwd = ""
u.Salt = ""
u.PasswdHashAlgo = ""
return nil
}
if u.Salt, err = GetUserSalt(); err != nil {
return err
}
@ -443,6 +424,17 @@ func (u *User) GetDisplayName() string {
return u.Name
}
// GetCompleteName returns the the full name and username in the form of
// "Full Name (@username)" if full name is not empty, otherwise it returns
// "@username".
func (u *User) GetCompleteName() string {
trimmedFullName := strings.TrimSpace(u.FullName)
if len(trimmedFullName) > 0 {
return fmt.Sprintf("%s (@%s)", trimmedFullName, u.Name)
}
return fmt.Sprintf("@%s", u.Name)
}
func gitSafeName(name string) string {
return strings.TrimSpace(strings.NewReplacer("\n", "", "<", "", ">", "").Replace(name))
}
@ -477,21 +469,6 @@ func (u *User) IsMailable() bool {
return u.IsActive
}
// EmailNotifications returns the User's email notification preference
func (u *User) EmailNotifications() string {
return u.EmailNotificationsPreference
}
// SetEmailNotifications sets the user's email notification preference
func SetEmailNotifications(ctx context.Context, u *User, set string) error {
u.EmailNotificationsPreference = set
if err := UpdateUserCols(ctx, u, "email_notifications_preference"); err != nil {
log.Error("SetEmailNotifications: %v", err)
return err
}
return nil
}
// IsUserExist checks if given user name exist,
// the user name should be noncased unique.
// If uid is presented, then check will rule out that one,
@ -694,8 +671,13 @@ func CreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOve
if u.Rands, err = GetUserSalt(); err != nil {
return err
}
if err = u.SetPassword(u.Passwd); err != nil {
return err
if u.Passwd != "" {
if err = u.SetPassword(u.Passwd); err != nil {
return err
}
} else {
u.Salt = ""
u.PasswdHashAlgo = ""
}
// save changes to database
@ -806,24 +788,6 @@ func VerifyUserActiveCode(ctx context.Context, code string) (user *User) {
return nil
}
// checkDupEmail checks whether there are the same email with the user
func checkDupEmail(ctx context.Context, u *User) error {
u.Email = strings.ToLower(u.Email)
has, err := db.GetEngine(ctx).
Where("id!=?", u.ID).
And("type=?", u.Type).
And("email=?", u.Email).
Get(new(User))
if err != nil {
return err
} else if has {
return ErrEmailAlreadyUsed{
Email: u.Email,
}
}
return nil
}
// ValidateUser check if user is valid to insert / update into database
func ValidateUser(u *User, cols ...string) error {
if len(cols) == 0 || util.SliceContainsString(cols, "visibility", true) {
@ -832,81 +796,9 @@ func ValidateUser(u *User, cols ...string) error {
}
}
if len(cols) == 0 || util.SliceContainsString(cols, "email", true) {
u.Email = strings.ToLower(u.Email)
if err := ValidateEmail(u.Email); err != nil {
return err
}
}
return nil
}
// UpdateUser updates user's information.
func UpdateUser(ctx context.Context, u *User, changePrimaryEmail bool, cols ...string) error {
err := ValidateUser(u, cols...)
if err != nil {
return err
}
e := db.GetEngine(ctx)
if changePrimaryEmail {
var emailAddress EmailAddress
has, err := e.Where("lower_email=?", strings.ToLower(u.Email)).Get(&emailAddress)
if err != nil {
return err
}
if has && emailAddress.UID != u.ID {
return ErrEmailAlreadyUsed{
Email: u.Email,
}
}
// 1. Update old primary email
if _, err = e.Where("uid=? AND is_primary=?", u.ID, true).Cols("is_primary").Update(&EmailAddress{
IsPrimary: false,
}); err != nil {
return err
}
if !has {
emailAddress.Email = u.Email
emailAddress.UID = u.ID
emailAddress.IsActivated = true
emailAddress.IsPrimary = true
if _, err := e.Insert(&emailAddress); err != nil {
return err
}
} else if _, err := e.ID(emailAddress.ID).Cols("is_primary").Update(&EmailAddress{
IsPrimary: true,
}); err != nil {
return err
}
} else if !u.IsOrganization() { // check if primary email in email_address table
primaryEmailExist, err := e.Where("uid=? AND is_primary=?", u.ID, true).Exist(&EmailAddress{})
if err != nil {
return err
}
if !primaryEmailExist {
if _, err := e.Insert(&EmailAddress{
Email: u.Email,
UID: u.ID,
IsActivated: true,
IsPrimary: true,
}); err != nil {
return err
}
}
}
if len(cols) == 0 {
_, err = e.ID(u.ID).AllCols().Update(u)
} else {
_, err = e.ID(u.ID).Cols(cols...).Update(u)
}
return err
}
// UpdateUserCols update user according special columns
func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
if err := ValidateUser(u, cols...); err != nil {
@ -917,25 +809,6 @@ func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
return err
}
// UpdateUserSetting updates user's settings.
func UpdateUserSetting(ctx context.Context, u *User) (err error) {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
if !u.IsOrganization() {
if err = checkDupEmail(ctx, u); err != nil {
return err
}
}
if err = UpdateUser(ctx, u, false); err != nil {
return err
}
return committer.Commit()
}
// GetInactiveUsers gets all inactive users
func GetInactiveUsers(ctx context.Context, olderThan time.Duration) ([]*User, error) {
var cond builder.Cond = builder.Eq{"is_active": false}
@ -1033,7 +906,7 @@ func GetUserEmailsByNames(ctx context.Context, names []string) []string {
if err != nil {
continue
}
if u.IsMailable() && u.EmailNotifications() != EmailNotificationsDisabled {
if u.IsMailable() && u.EmailNotificationsPreference != EmailNotificationsDisabled {
mails = append(mails, u.Email)
}
}

View File

@ -101,13 +101,13 @@ func TestSearchUsers(t *testing.T) {
}
testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}},
[]int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34})
[]int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37})
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse},
[]int64{9})
testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
[]int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34})
[]int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37})
testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
[]int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
@ -123,7 +123,7 @@ func TestSearchUsers(t *testing.T) {
[]int64{29})
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: util.OptionalBoolTrue},
[]int64{30})
[]int64{37})
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: util.OptionalBoolTrue},
[]int64{24})
@ -147,20 +147,7 @@ func TestEmailNotificationPreferences(t *testing.T) {
{user_model.EmailNotificationsOnMention, 9},
} {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.userID})
assert.Equal(t, test.expected, user.EmailNotifications())
// Try all possible settings
assert.NoError(t, user_model.SetEmailNotifications(db.DefaultContext, user, user_model.EmailNotificationsEnabled))
assert.Equal(t, user_model.EmailNotificationsEnabled, user.EmailNotifications())
assert.NoError(t, user_model.SetEmailNotifications(db.DefaultContext, user, user_model.EmailNotificationsOnMention))
assert.Equal(t, user_model.EmailNotificationsOnMention, user.EmailNotifications())
assert.NoError(t, user_model.SetEmailNotifications(db.DefaultContext, user, user_model.EmailNotificationsDisabled))
assert.Equal(t, user_model.EmailNotificationsDisabled, user.EmailNotifications())
assert.NoError(t, user_model.SetEmailNotifications(db.DefaultContext, user, user_model.EmailNotificationsAndYourOwn))
assert.Equal(t, user_model.EmailNotificationsAndYourOwn, user.EmailNotifications())
assert.Equal(t, test.expected, user.EmailNotificationsPreference)
}
}
@ -343,42 +330,6 @@ func TestGetMaileableUsersByIDs(t *testing.T) {
}
}
func TestUpdateUser(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
user.KeepActivityPrivate = true
assert.NoError(t, user_model.UpdateUser(db.DefaultContext, user, false))
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
assert.True(t, user.KeepActivityPrivate)
setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, false}
user.KeepActivityPrivate = false
user.Visibility = structs.VisibleTypePrivate
assert.Error(t, user_model.UpdateUser(db.DefaultContext, user, false))
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
assert.True(t, user.KeepActivityPrivate)
newEmail := "new_" + user.Email
user.Email = newEmail
assert.NoError(t, user_model.UpdateUser(db.DefaultContext, user, true))
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
assert.Equal(t, newEmail, user.Email)
user.Email = "no mail@mail.org"
assert.Error(t, user_model.UpdateUser(db.DefaultContext, user, true))
}
func TestUpdateUserEmailAlreadyUsed(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
user2.Email = org3.Email
err := user_model.UpdateUser(db.DefaultContext, user2, true)
assert.True(t, user_model.IsErrEmailAlreadyUsed(err))
}
func TestNewUserRedirect(t *testing.T) {
// redirect to a completely new name
assert.NoError(t, unittest.PrepareTestDatabase())
@ -534,14 +485,12 @@ func Test_ValidateUser(t *testing.T) {
}()
setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, true}
kases := map[*user_model.User]bool{
{ID: 1, Visibility: structs.VisibleTypePublic}: true,
{ID: 2, Visibility: structs.VisibleTypeLimited}: false,
{ID: 2, Visibility: structs.VisibleTypeLimited, Email: "invalid"}: false,
{ID: 2, Visibility: structs.VisibleTypePrivate, Email: "valid@valid.com"}: true,
{ID: 1, Visibility: structs.VisibleTypePublic}: true,
{ID: 2, Visibility: structs.VisibleTypeLimited}: false,
{ID: 2, Visibility: structs.VisibleTypePrivate}: true,
}
for kase, expected := range kases {
err := user_model.ValidateUser(kase)
assert.EqualValues(t, expected, err == nil, fmt.Sprintf("case: %+v", kase))
assert.EqualValues(t, expected, nil == user_model.ValidateUser(kase), fmt.Sprintf("case: %+v", kase))
}
}

View File

@ -146,6 +146,41 @@ func DetectWorkflows(
return workflows, schedules, nil
}
func DetectScheduledWorkflows(gitRepo *git.Repository, commit *git.Commit) ([]*DetectedWorkflow, error) {
entries, err := ListWorkflows(commit)
if err != nil {
return nil, err
}
wfs := make([]*DetectedWorkflow, 0, len(entries))
for _, entry := range entries {
content, err := GetContentFromEntry(entry)
if err != nil {
return nil, err
}
// one workflow may have multiple events
events, err := GetEventsFromContent(content)
if err != nil {
log.Warn("ignore invalid workflow %q: %v", entry.Name(), err)
continue
}
for _, evt := range events {
if evt.IsSchedule() {
log.Trace("detect scheduled workflow: %q", entry.Name())
dwf := &DetectedWorkflow{
EntryName: entry.Name(),
TriggerEvent: evt,
Content: content,
}
wfs = append(wfs, dwf)
}
}
}
return wfs, nil
}
func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) bool {
if !canGithubEventMatch(evt.Name, triggedEvent) {
return false

View File

@ -5,8 +5,9 @@ package password
import (
"bytes"
goContext "context"
"context"
"crypto/rand"
"errors"
"math/big"
"strings"
"sync"
@ -15,6 +16,11 @@ import (
"code.gitea.io/gitea/modules/translation"
)
var (
ErrComplexity = errors.New("password not complex enough")
ErrMinLength = errors.New("password not long enough")
)
// complexity contains information about a particular kind of password complexity
type complexity struct {
ValidChars string
@ -101,11 +107,14 @@ func Generate(n int) (string, error) {
}
buffer[j] = validChars[rnd.Int64()]
}
pwned, err := IsPwned(goContext.Background(), string(buffer))
if err != nil {
if err := IsPwned(context.Background(), string(buffer)); err != nil {
if errors.Is(err, ErrIsPwned) {
continue
}
return "", err
}
if IsComplexEnough(string(buffer)) && !pwned && string(buffer[0]) != " " && string(buffer[n-1]) != " " {
if IsComplexEnough(string(buffer)) && string(buffer[0]) != " " && string(buffer[n-1]) != " " {
return string(buffer), nil
}
}

View File

@ -5,24 +5,48 @@ package password
import (
"context"
"errors"
"fmt"
"code.gitea.io/gitea/modules/auth/password/pwn"
"code.gitea.io/gitea/modules/setting"
)
var ErrIsPwned = errors.New("password has been pwned")
type ErrIsPwnedRequest struct {
err error
}
func IsErrIsPwnedRequest(err error) bool {
_, ok := err.(ErrIsPwnedRequest)
return ok
}
func (err ErrIsPwnedRequest) Error() string {
return fmt.Sprintf("using Have-I-Been-Pwned service failed: %v", err.err)
}
func (err ErrIsPwnedRequest) Unwrap() error {
return err.err
}
// IsPwned checks whether a password has been pwned
// NOTE: This func returns true if it encounters an error under the assumption that you ALWAYS want to check against
// HIBP, so not getting a response should block a password until it can be verified.
func IsPwned(ctx context.Context, password string) (bool, error) {
// If a password has not been pwned, no error is returned.
func IsPwned(ctx context.Context, password string) error {
if !setting.PasswordCheckPwn {
return false, nil
return nil
}
client := pwn.New(pwn.WithContext(ctx))
count, err := client.CheckPassword(password, true)
if err != nil {
return true, err
return ErrIsPwnedRequest{err}
}
return count > 0, nil
if count > 0 {
return ErrIsPwned
}
return nil
}

View File

@ -73,7 +73,7 @@ func newRequest(ctx context.Context, method, url string, body io.ReadCloser) (*h
// because artificial responses will be added to the response
// For more information, see https://www.troyhunt.com/enhancing-pwned-passwords-privacy-with-padding/
func (c *Client) CheckPassword(pw string, padding bool) (int, error) {
if strings.TrimSpace(pw) == "" {
if pw == "" {
return -1, ErrEmptyPassword
}

View File

@ -4,13 +4,14 @@
package pwn
import (
"errors"
"math/rand"
"net/http"
"os"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
var client = New(WithHTTP(&http.Client{
@ -25,78 +26,44 @@ func TestMain(m *testing.M) {
func TestPassword(t *testing.T) {
// Check input error
_, err := client.CheckPassword("", false)
if err == nil {
t.Log("blank input should return an error")
t.Fail()
}
if !errors.Is(err, ErrEmptyPassword) {
t.Log("blank input should return ErrEmptyPassword")
t.Fail()
}
assert.ErrorIs(t, err, ErrEmptyPassword, "blank input should return ErrEmptyPassword")
// Should fail
fail := "password1234"
count, err := client.CheckPassword(fail, false)
if err != nil {
t.Log(err)
t.Fail()
}
if count == 0 {
t.Logf("%s should fail as a password\n", fail)
t.Fail()
}
assert.NotEmpty(t, count, "%s should fail as a password", fail)
assert.NoError(t, err)
// Should fail (with padding)
failPad := "administrator"
count, err = client.CheckPassword(failPad, true)
if err != nil {
t.Log(err)
t.Fail()
}
if count == 0 {
t.Logf("%s should fail as a password\n", failPad)
t.Fail()
}
assert.NotEmpty(t, count, "%s should fail as a password", failPad)
assert.NoError(t, err)
// Checking for a "good" password isn't going to be perfect, but we can give it a good try
// with hopefully minimal error. Try five times?
var good bool
var pw string
for idx := 0; idx <= 5; idx++ {
pw = testPassword()
count, err = client.CheckPassword(pw, false)
if err != nil {
t.Log(err)
t.Fail()
assert.Condition(t, func() bool {
for i := 0; i <= 5; i++ {
count, err = client.CheckPassword(testPassword(), false)
assert.NoError(t, err)
if count == 0 {
return true
}
}
if count == 0 {
good = true
break
}
}
if !good {
t.Log("no generated passwords passed. there is a chance this is a fluke")
t.Fail()
}
return false
}, "no generated passwords passed. there is a chance this is a fluke")
// Again, but with padded responses
good = false
for idx := 0; idx <= 5; idx++ {
pw = testPassword()
count, err = client.CheckPassword(pw, true)
if err != nil {
t.Log(err)
t.Fail()
assert.Condition(t, func() bool {
for i := 0; i <= 5; i++ {
count, err = client.CheckPassword(testPassword(), true)
assert.NoError(t, err)
if count == 0 {
return true
}
}
if count == 0 {
good = true
break
}
}
if !good {
t.Log("no generated passwords passed. there is a chance this is a fluke")
t.Fail()
}
return false
}, "no generated passwords passed. there is a chance this is a fluke")
}
// Credit to https://golangbyexample.com/generate-random-password-golang/

View File

@ -22,17 +22,21 @@ import (
// UTF8BOM is the utf-8 byte-order marker
var UTF8BOM = []byte{'\xef', '\xbb', '\xbf'}
type ConvertOpts struct {
KeepBOM bool
}
// ToUTF8WithFallbackReader detects the encoding of content and converts to UTF-8 reader if possible
func ToUTF8WithFallbackReader(rd io.Reader) io.Reader {
func ToUTF8WithFallbackReader(rd io.Reader, opts ConvertOpts) io.Reader {
buf := make([]byte, 2048)
n, err := util.ReadAtMost(rd, buf)
if err != nil {
return io.MultiReader(bytes.NewReader(RemoveBOMIfPresent(buf[:n])), rd)
return io.MultiReader(bytes.NewReader(MaybeRemoveBOM(buf[:n], opts)), rd)
}
charsetLabel, err := DetectEncoding(buf[:n])
if err != nil || charsetLabel == "UTF-8" {
return io.MultiReader(bytes.NewReader(RemoveBOMIfPresent(buf[:n])), rd)
return io.MultiReader(bytes.NewReader(MaybeRemoveBOM(buf[:n], opts)), rd)
}
encoding, _ := charset.Lookup(charsetLabel)
@ -42,20 +46,20 @@ func ToUTF8WithFallbackReader(rd io.Reader) io.Reader {
return transform.NewReader(
io.MultiReader(
bytes.NewReader(RemoveBOMIfPresent(buf[:n])),
bytes.NewReader(MaybeRemoveBOM(buf[:n], opts)),
rd,
),
encoding.NewDecoder(),
)
}
// ToUTF8WithErr converts content to UTF8 encoding
func ToUTF8WithErr(content []byte) (string, error) {
// ToUTF8 converts content to UTF8 encoding
func ToUTF8(content []byte, opts ConvertOpts) (string, error) {
charsetLabel, err := DetectEncoding(content)
if err != nil {
return "", err
} else if charsetLabel == "UTF-8" {
return string(RemoveBOMIfPresent(content)), nil
return string(MaybeRemoveBOM(content, opts)), nil
}
encoding, _ := charset.Lookup(charsetLabel)
@ -70,28 +74,22 @@ func ToUTF8WithErr(content []byte) (string, error) {
result = append(result, content[n:]...)
}
result = RemoveBOMIfPresent(result)
result = MaybeRemoveBOM(result, opts)
return string(result), err
}
// ToUTF8WithFallback detects the encoding of content and converts to UTF-8 if possible
func ToUTF8WithFallback(content []byte) []byte {
bs, _ := io.ReadAll(ToUTF8WithFallbackReader(bytes.NewReader(content)))
func ToUTF8WithFallback(content []byte, opts ConvertOpts) []byte {
bs, _ := io.ReadAll(ToUTF8WithFallbackReader(bytes.NewReader(content), opts))
return bs
}
// ToUTF8 converts content to UTF8 encoding and ignore error
func ToUTF8(content string) string {
res, _ := ToUTF8WithErr([]byte(content))
return res
}
// ToUTF8DropErrors makes sure the return string is valid utf-8; attempts conversion if possible
func ToUTF8DropErrors(content []byte) []byte {
func ToUTF8DropErrors(content []byte, opts ConvertOpts) []byte {
charsetLabel, err := DetectEncoding(content)
if err != nil || charsetLabel == "UTF-8" {
return RemoveBOMIfPresent(content)
return MaybeRemoveBOM(content, opts)
}
encoding, _ := charset.Lookup(charsetLabel)
@ -117,11 +115,14 @@ func ToUTF8DropErrors(content []byte) []byte {
}
}
return RemoveBOMIfPresent(decoded)
return MaybeRemoveBOM(decoded, opts)
}
// RemoveBOMIfPresent removes a UTF-8 BOM from a []byte
func RemoveBOMIfPresent(content []byte) []byte {
// MaybeRemoveBOM removes a UTF-8 BOM from a []byte when opts.KeepBOM is false
func MaybeRemoveBOM(content []byte, opts ConvertOpts) []byte {
if opts.KeepBOM {
return content
}
if len(content) > 2 && bytes.Equal(content[0:3], UTF8BOM) {
return content[3:]
}

View File

@ -30,15 +30,15 @@ func resetDefaultCharsetsOrder() {
}
}
func TestRemoveBOMIfPresent(t *testing.T) {
res := RemoveBOMIfPresent([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
func TestMaybeRemoveBOM(t *testing.T) {
res := MaybeRemoveBOM([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, ConvertOpts{})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
res = RemoveBOMIfPresent([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
res = MaybeRemoveBOM([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, ConvertOpts{})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
}
func TestToUTF8WithErr(t *testing.T) {
func TestToUTF8(t *testing.T) {
resetDefaultCharsetsOrder()
var res string
var err error
@ -47,53 +47,53 @@ func TestToUTF8WithErr(t *testing.T) {
// locale, so some conversions might behave differently. For that reason, we don't
// depend on particular conversions but in expected behaviors.
res, err = ToUTF8WithErr([]byte{0x41, 0x42, 0x43})
res, err = ToUTF8([]byte{0x41, 0x42, 0x43}, ConvertOpts{})
assert.NoError(t, err)
assert.Equal(t, "ABC", res)
// "áéíóú"
res, err = ToUTF8WithErr([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
res, err = ToUTF8([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, ConvertOpts{})
assert.NoError(t, err)
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, []byte(res))
// "áéíóú"
res, err = ToUTF8WithErr([]byte{
res, err = ToUTF8([]byte{
0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3,
0xc3, 0xba,
})
}, ConvertOpts{})
assert.NoError(t, err)
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, []byte(res))
res, err = ToUTF8WithErr([]byte{
res, err = ToUTF8([]byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63,
0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73, 0x41, 0x41, 0x41, 0x2e,
})
}, ConvertOpts{})
assert.NoError(t, err)
stringMustStartWith(t, "Hola,", res)
stringMustEndWith(t, "AAA.", res)
res, err = ToUTF8WithErr([]byte{
res, err = ToUTF8([]byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63,
0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73, 0x41, 0x41, 0x41, 0x2e,
})
}, ConvertOpts{})
assert.NoError(t, err)
stringMustStartWith(t, "Hola,", res)
stringMustEndWith(t, "AAA.", res)
res, err = ToUTF8WithErr([]byte{
res, err = ToUTF8([]byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63,
0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73, 0x41, 0x41, 0x41, 0x2e,
})
}, ConvertOpts{})
assert.NoError(t, err)
stringMustStartWith(t, "Hola,", res)
stringMustEndWith(t, "AAA.", res)
// Japanese (Shift-JIS)
// 日属秘ぞしちゅ。
res, err = ToUTF8WithErr([]byte{
res, err = ToUTF8([]byte{
0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82,
0xBF, 0x82, 0xE3, 0x81, 0x42,
})
}, ConvertOpts{})
assert.NoError(t, err)
assert.Equal(t, []byte{
0xE6, 0x97, 0xA5, 0xE5, 0xB1, 0x9E, 0xE7, 0xA7, 0x98, 0xE3,
@ -101,7 +101,7 @@ func TestToUTF8WithErr(t *testing.T) {
},
[]byte(res))
res, err = ToUTF8WithErr([]byte{0x00, 0x00, 0x00, 0x00})
res, err = ToUTF8([]byte{0x00, 0x00, 0x00, 0x00}, ConvertOpts{})
assert.NoError(t, err)
assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00}, []byte(res))
}
@ -109,22 +109,22 @@ func TestToUTF8WithErr(t *testing.T) {
func TestToUTF8WithFallback(t *testing.T) {
resetDefaultCharsetsOrder()
// "ABC"
res := ToUTF8WithFallback([]byte{0x41, 0x42, 0x43})
res := ToUTF8WithFallback([]byte{0x41, 0x42, 0x43}, ConvertOpts{})
assert.Equal(t, []byte{0x41, 0x42, 0x43}, res)
// "áéíóú"
res = ToUTF8WithFallback([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
res = ToUTF8WithFallback([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, ConvertOpts{})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// UTF8 BOM + "áéíóú"
res = ToUTF8WithFallback([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
res = ToUTF8WithFallback([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, ConvertOpts{})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// "Hola, así cómo ños"
res = ToUTF8WithFallback([]byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63,
0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73,
})
}, ConvertOpts{})
assert.Equal(t, []byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63,
0xC3, 0xB3, 0x6D, 0x6F, 0x20, 0xC3, 0xB1, 0x6F, 0x73,
@ -133,126 +133,65 @@ func TestToUTF8WithFallback(t *testing.T) {
// "Hola, así cómo "
minmatch := []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63, 0xC3, 0xB3, 0x6D, 0x6F, 0x20}
res = ToUTF8WithFallback([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73})
res = ToUTF8WithFallback([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73}, ConvertOpts{})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
res = ToUTF8WithFallback([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73})
res = ToUTF8WithFallback([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73}, ConvertOpts{})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
// Japanese (Shift-JIS)
// "日属秘ぞしちゅ。"
res = ToUTF8WithFallback([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42})
res = ToUTF8WithFallback([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42}, ConvertOpts{})
assert.Equal(t, []byte{
0xE6, 0x97, 0xA5, 0xE5, 0xB1, 0x9E, 0xE7, 0xA7, 0x98, 0xE3,
0x81, 0x9E, 0xE3, 0x81, 0x97, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x85, 0xE3, 0x80, 0x82,
}, res)
res = ToUTF8WithFallback([]byte{0x00, 0x00, 0x00, 0x00})
res = ToUTF8WithFallback([]byte{0x00, 0x00, 0x00, 0x00}, ConvertOpts{})
assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00}, res)
}
func TestToUTF8(t *testing.T) {
resetDefaultCharsetsOrder()
// Note: golang compiler seems so behave differently depending on the current
// locale, so some conversions might behave differently. For that reason, we don't
// depend on particular conversions but in expected behaviors.
res := ToUTF8(string([]byte{0x41, 0x42, 0x43}))
assert.Equal(t, "ABC", res)
// "áéíóú"
res = ToUTF8(string([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}))
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, []byte(res))
// BOM + "áéíóú"
res = ToUTF8(string([]byte{
0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3,
0xc3, 0xba,
}))
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, []byte(res))
// Latin1
// Hola, así cómo ños
res = ToUTF8(string([]byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63,
0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73,
}))
assert.Equal(t, []byte{
0x48, 0x6f, 0x6c, 0x61, 0x2c, 0x20, 0x61, 0x73, 0xc3, 0xad, 0x20, 0x63,
0xc3, 0xb3, 0x6d, 0x6f, 0x20, 0xc3, 0xb1, 0x6f, 0x73,
}, []byte(res))
// Latin1
// Hola, así cómo \x07ños
res = ToUTF8(string([]byte{
0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63,
0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73,
}))
// Hola,
bytesMustStartWith(t, []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C}, []byte(res))
// This test FAILS
// res = ToUTF8("Hola, así cómo \x81ños")
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
// assert.Regexp(t, "^Hola, así cómo", res)
// Japanese (Shift-JIS)
// 日属秘ぞしちゅ。
res = ToUTF8(string([]byte{
0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82,
0xBF, 0x82, 0xE3, 0x81, 0x42,
}))
assert.Equal(t, []byte{
0xE6, 0x97, 0xA5, 0xE5, 0xB1, 0x9E, 0xE7, 0xA7, 0x98, 0xE3,
0x81, 0x9E, 0xE3, 0x81, 0x97, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x85, 0xE3, 0x80, 0x82,
},
[]byte(res))
res = ToUTF8("\x00\x00\x00\x00")
assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00}, []byte(res))
}
func TestToUTF8DropErrors(t *testing.T) {
resetDefaultCharsetsOrder()
// "ABC"
res := ToUTF8DropErrors([]byte{0x41, 0x42, 0x43})
res := ToUTF8DropErrors([]byte{0x41, 0x42, 0x43}, ConvertOpts{})
assert.Equal(t, []byte{0x41, 0x42, 0x43}, res)
// "áéíóú"
res = ToUTF8DropErrors([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
res = ToUTF8DropErrors([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, ConvertOpts{})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// UTF8 BOM + "áéíóú"
res = ToUTF8DropErrors([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})
res = ToUTF8DropErrors([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, ConvertOpts{})
assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res)
// "Hola, así cómo ños"
res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73})
res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73}, ConvertOpts{})
assert.Equal(t, []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73}, res[:8])
assert.Equal(t, []byte{0x73}, res[len(res)-1:])
// "Hola, así cómo "
minmatch := []byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xC3, 0xAD, 0x20, 0x63, 0xC3, 0xB3, 0x6D, 0x6F, 0x20}
res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73})
res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73}, ConvertOpts{})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73})
res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73}, ConvertOpts{})
// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those
assert.Equal(t, minmatch, res[0:len(minmatch)])
// Japanese (Shift-JIS)
// "日属秘ぞしちゅ。"
res = ToUTF8DropErrors([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42})
res = ToUTF8DropErrors([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42}, ConvertOpts{})
assert.Equal(t, []byte{
0xE6, 0x97, 0xA5, 0xE5, 0xB1, 0x9E, 0xE7, 0xA7, 0x98, 0xE3,
0x81, 0x9E, 0xE3, 0x81, 0x97, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x85, 0xE3, 0x80, 0x82,
}, res)
res = ToUTF8DropErrors([]byte{0x00, 0x00, 0x00, 0x00})
res = ToUTF8DropErrors([]byte{0x00, 0x00, 0x00, 0x00}, ConvertOpts{})
assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00}, res)
}
@ -302,10 +241,6 @@ func stringMustEndWith(t *testing.T, expected, value string) {
assert.Equal(t, expected, value[len(value)-len(expected):])
}
func bytesMustStartWith(t *testing.T, expected, value []byte) {
assert.Equal(t, expected, value[:len(expected)])
}
func TestToUTF8WithFallbackReader(t *testing.T) {
resetDefaultCharsetsOrder()
@ -317,7 +252,7 @@ func TestToUTF8WithFallbackReader(t *testing.T) {
}
input = input[:testLen]
input += "// Выключаем"
rd := ToUTF8WithFallbackReader(bytes.NewReader([]byte(input)))
rd := ToUTF8WithFallbackReader(bytes.NewReader([]byte(input)), ConvertOpts{})
r, _ := io.ReadAll(rd)
assert.EqualValuesf(t, input, string(r), "testing string len=%d", testLen)
}

View File

@ -11,11 +11,11 @@ import (
"net/url"
"strings"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
mc "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@ -224,7 +224,7 @@ func APIContexter() func(http.Handler) http.Handler {
defer baseCleanUp()
ctx.Base.AppendContextValue(apiContextKey, ctx)
ctx.Base.AppendContextValueFunc(git.RepositoryContextKey, func() any { return ctx.Repo.GitRepo })
ctx.Base.AppendContextValueFunc(gitrepo.RepositoryContextKey, func() any { return ctx.Repo.GitRepo })
// If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") {
@ -278,10 +278,9 @@ func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) (cancel context
// For API calls.
if ctx.Repo.GitRepo == nil {
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
gitRepo, err := git.OpenRepository(ctx, repoPath)
gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
if err != nil {
ctx.Error(http.StatusInternalServerError, "RepoRef Invalid repo "+repoPath, err)
ctx.Error(http.StatusInternalServerError, fmt.Sprintf("Open Repository %v failed", ctx.Repo.Repository.FullName()), err)
return cancel
}
ctx.Repo.GitRepo = gitRepo

View File

@ -17,7 +17,7 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
mc "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
@ -163,7 +163,7 @@ func Contexter() func(next http.Handler) http.Handler {
ctx.Data["PageData"] = ctx.PageData
ctx.Base.AppendContextValue(WebContextKey, ctx)
ctx.Base.AppendContextValueFunc(git.RepositoryContextKey, func() any { return ctx.Repo.GitRepo })
ctx.Base.AppendContextValueFunc(gitrepo.RepositoryContextKey, func() any { return ctx.Repo.GitRepo })
ctx.Csrf = PrepareCSRFProtector(csrfOpts, ctx)

View File

@ -93,7 +93,7 @@ func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, string, any))
}
func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.AccessMode, error) {
if setting.Service.RequireSignInView && doer == nil {
if setting.Service.RequireSignInView && (doer == nil || doer.IsGhost()) {
return perm.AccessModeNone, nil
}

View File

@ -23,6 +23,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
code_indexer "code.gitea.io/gitea/modules/indexer/code"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
@ -633,7 +634,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
return nil
}
gitRepo, err := git.OpenRepository(ctx, repo_model.RepoPath(userName, repoName))
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
if err != nil {
if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
@ -645,7 +646,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
}
return nil
}
ctx.ServerError("RepoAssignment Invalid repo "+repo_model.RepoPath(userName, repoName), err)
ctx.ServerError("RepoAssignment Invalid repo "+repo.FullName(), err)
return nil
}
if ctx.Repo.GitRepo != nil {
@ -921,10 +922,9 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
)
if ctx.Repo.GitRepo == nil {
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
ctx.Repo.GitRepo, err = git.OpenRepository(ctx, repoPath)
ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
if err != nil {
ctx.ServerError("RepoRef Invalid repo "+repoPath, err)
ctx.ServerError(fmt.Sprintf("Open Repository %v failed", ctx.Repo.Repository.FullName()), err)
return nil
}
// We opened it, we should close it

View File

@ -18,7 +18,7 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/web/middleware"
@ -107,7 +107,7 @@ func LoadRepoCommit(t *testing.T, ctx gocontext.Context) {
assert.FailNow(t, "context is not *context.Context or *context.APIContext")
}
gitRepo, err := git.OpenRepository(ctx, repo.Repository.RepoPath())
gitRepo, err := gitrepo.OpenRepository(ctx, repo.Repository)
assert.NoError(t, err)
defer gitRepo.Close()
branch, err := gitRepo.GetHEADBranch()
@ -137,7 +137,7 @@ func LoadUser(t *testing.T, ctx gocontext.Context, userID int64) {
func LoadGitRepo(t *testing.T, ctx *context.Context) {
assert.NoError(t, ctx.Repo.Repository.LoadOwner(ctx))
var err error
ctx.Repo.GitRepo, err = git.OpenRepository(ctx, ctx.Repo.Repository.RepoPath())
ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
assert.NoError(t, err)
}

View File

@ -0,0 +1,144 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package git
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
)
func TestReadingBlameOutputSha256(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
t.Run("Without .git-blame-ignore-revs", func(t *testing.T) {
repo, err := OpenRepository(ctx, "./tests/repos/repo5_pulls_sha256")
assert.NoError(t, err)
defer repo.Close()
commit, err := repo.GetCommit("0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345")
assert.NoError(t, err)
parts := []*BlamePart{
{
Sha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
Lines: []string{
"# test_repo",
"Test repository for testing migration from github to gitea",
},
},
{
Sha: "0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345",
Lines: []string{"", "Do not make any changes to this repo it is used for unit testing"},
PreviousSha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
PreviousPath: "README.md",
},
}
for _, bypass := range []bool{false, true} {
blameReader, err := CreateBlameReader(ctx, Sha256ObjectFormat, "./tests/repos/repo5_pulls_sha256", commit, "README.md", bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
assert.False(t, blameReader.UsesIgnoreRevs())
for _, part := range parts {
actualPart, err := blameReader.NextPart()
assert.NoError(t, err)
assert.Equal(t, part, actualPart)
}
// make sure all parts have been read
actualPart, err := blameReader.NextPart()
assert.Nil(t, actualPart)
assert.NoError(t, err)
}
})
t.Run("With .git-blame-ignore-revs", func(t *testing.T) {
repo, err := OpenRepository(ctx, "./tests/repos/repo6_blame_sha256")
assert.NoError(t, err)
defer repo.Close()
full := []*BlamePart{
{
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
Lines: []string{"line", "line"},
},
{
Sha: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
Lines: []string{"changed line"},
PreviousSha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
PreviousPath: "blame.txt",
},
{
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
Lines: []string{"line", "line", ""},
},
}
cases := []struct {
CommitID string
UsesIgnoreRevs bool
Bypass bool
Parts []*BlamePart
}{
{
CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
UsesIgnoreRevs: true,
Bypass: false,
Parts: []*BlamePart{
{
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
Lines: []string{"line", "line", "changed line", "line", "line", ""},
},
},
},
{
CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
UsesIgnoreRevs: false,
Bypass: true,
Parts: full,
},
{
CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
UsesIgnoreRevs: false,
Bypass: false,
Parts: full,
},
{
CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
UsesIgnoreRevs: false,
Bypass: false,
Parts: full,
},
}
for _, c := range cases {
commit, err := repo.GetCommit(c.CommitID)
assert.NoError(t, err)
blameReader, err := CreateBlameReader(ctx, repo.objectFormat, "./tests/repos/repo6_blame_sha256", commit, "blame.txt", c.Bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
assert.Equal(t, c.UsesIgnoreRevs, blameReader.UsesIgnoreRevs())
for _, part := range c.Parts {
actualPart, err := blameReader.NextPart()
assert.NoError(t, err)
assert.Equal(t, part, actualPart)
}
// make sure all parts have been read
actualPart, err := blameReader.NextPart()
assert.Nil(t, actualPart)
assert.NoError(t, err)
}
})
}

View File

@ -85,6 +85,8 @@ readLoop:
commit.Committer.Decode(data)
_, _ = payloadSB.Write(line)
case "gpgsig":
fallthrough
case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present.
_, _ = signatureSB.Write(data)
_ = signatureSB.WriteByte('\n')
pgpsig = true

View File

@ -0,0 +1,195 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build !gogit
package git
import (
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCommitsCountSha256(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
commitsCount, err := CommitsCount(DefaultContext,
CommitsCountOptions{
RepoPath: bareRepo1Path,
Revision: []string{"f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc"},
})
assert.NoError(t, err)
assert.Equal(t, int64(3), commitsCount)
}
func TestCommitsCountWithoutBaseSha256(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
commitsCount, err := CommitsCount(DefaultContext,
CommitsCountOptions{
RepoPath: bareRepo1Path,
Not: "main",
Revision: []string{"branch1"},
})
assert.NoError(t, err)
assert.Equal(t, int64(2), commitsCount)
}
func TestGetFullCommitIDSha256(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "f004f4")
assert.NoError(t, err)
assert.Equal(t, "f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc", id)
}
func TestGetFullCommitIDErrorSha256(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "unknown")
assert.Empty(t, id)
if assert.Error(t, err) {
assert.EqualError(t, err, "object does not exist [id: unknown, rel_path: ]")
}
}
func TestCommitFromReaderSha256(t *testing.T) {
commitString := `9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 commit 1114
tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
author Adam Majer <amajer@suse.de> 1698676906 +0100
committer Adam Majer <amajer@suse.de> 1698676906 +0100
gpgsig-sha256 -----BEGIN PGP SIGNATURE-----
` + " " + `
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
=xybZ
-----END PGP SIGNATURE-----
signed commit`
sha := &Sha256Hash{
0x94, 0x33, 0xb2, 0xa6, 0x2b, 0x96, 0x4c, 0x17, 0xa4, 0x48, 0x5a, 0xe1, 0x80, 0xf4, 0x5f, 0x59,
0x5d, 0x3e, 0x69, 0xd3, 0x1b, 0x78, 0x60, 0x87, 0x77, 0x5e, 0x28, 0xc6, 0xb6, 0x39, 0x9d, 0xf0,
}
gitRepo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare_sha256"))
assert.NoError(t, err)
assert.NotNil(t, gitRepo)
defer gitRepo.Close()
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
assert.NoError(t, err)
if !assert.NotNil(t, commitFromReader) {
return
}
assert.EqualValues(t, sha, commitFromReader.ID)
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
=xybZ
-----END PGP SIGNATURE-----
`, commitFromReader.Signature.Signature)
assert.EqualValues(t, `tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
author Adam Majer <amajer@suse.de> 1698676906 +0100
committer Adam Majer <amajer@suse.de> 1698676906 +0100
signed commit`, commitFromReader.Signature.Payload)
assert.EqualValues(t, "Adam Majer <amajer@suse.de>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
assert.EqualValues(t, commitFromReader, commitFromReader2)
}
func TestHasPreviousCommitSha256(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
repo, err := openRepositoryWithDefaultContext(bareRepo1Path)
assert.NoError(t, err)
defer repo.Close()
commit, err := repo.GetCommit("f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc")
assert.NoError(t, err)
parentSHA := MustIDFromString("b0ec7af4547047f12d5093e37ef8f1b3b5415ed8ee17894d43a34d7d34212e9c")
notParentSHA := MustIDFromString("42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236")
assert.Equal(t, repo.objectFormat, parentSHA.Type())
assert.Equal(t, repo.objectFormat.Name(), "sha256")
haz, err := commit.HasPreviousCommit(parentSHA)
assert.NoError(t, err)
assert.True(t, haz)
hazNot, err := commit.HasPreviousCommit(notParentSHA)
assert.NoError(t, err)
assert.False(t, hazNot)
selfNot, err := commit.HasPreviousCommit(commit.ID)
assert.NoError(t, err)
assert.False(t, selfNot)
}
func TestGetCommitFileStatusMergesSha256(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo6_merge_sha256")
commitFileStatus, err := GetCommitFileStatus(DefaultContext, bareRepo1Path, "d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1")
assert.NoError(t, err)
expected := CommitFileStatus{
[]string{
"add_file.txt",
},
[]string{},
[]string{
"to_modify.txt",
},
}
assert.Equal(t, expected.Added, commitFileStatus.Added)
assert.Equal(t, expected.Removed, commitFileStatus.Removed)
assert.Equal(t, expected.Modified, commitFileStatus.Modified)
expected = CommitFileStatus{
[]string{},
[]string{
"to_remove.txt",
},
[]string{},
}
commitFileStatus, err = GetCommitFileStatus(DefaultContext, bareRepo1Path, "da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172")
assert.NoError(t, err)
assert.Equal(t, expected.Added, commitFileStatus.Added)
assert.Equal(t, expected.Removed, commitFileStatus.Removed)
assert.Equal(t, expected.Modified, commitFileStatus.Modified)
}

View File

@ -185,7 +185,13 @@ func InitFull(ctx context.Context) (err error) {
globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
}
SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil
SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil && !isGogit
if SupportHashSha256 {
SupportedObjectFormats = append(SupportedObjectFormats, Sha256ObjectFormat)
} else {
log.Warn("sha256 hash support is disabled - requires Git >= 2.42. Gogit is currently unsupported")
}
if setting.LFS.StartServer {
if CheckGitVersionAtLeast("2.1.2") != nil {
return errors.New("LFS server support requires Git >= 2.1.2")

View File

@ -5,6 +5,7 @@ package git
import (
"crypto/sha1"
"crypto/sha256"
"regexp"
"strconv"
)
@ -12,6 +13,9 @@ import (
// sha1Pattern can be used to determine if a string is an valid sha
var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
// sha256Pattern can be used to determine if a string is an valid sha
var sha256Pattern = regexp.MustCompile(`^[0-9a-f]{4,64}$`)
type ObjectFormat interface {
// Name returns the name of the object format
Name() string
@ -29,11 +33,12 @@ type ObjectFormat interface {
ComputeHash(t ObjectType, content []byte) ObjectID
}
/* SHA1 Type */
type Sha1ObjectFormatImpl struct{}
var (
emptyObjectID = &Sha1Hash{}
emptyTree = &Sha1Hash{
emptySha1ObjectID = &Sha1Hash{}
emptySha1Tree = &Sha1Hash{
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
}
@ -41,11 +46,11 @@ var (
func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
return emptyObjectID
return emptySha1ObjectID
}
func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
return emptyTree
return emptySha1Tree
}
func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
func (Sha1ObjectFormatImpl) IsValid(input string) bool {
@ -72,11 +77,59 @@ func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID
return &sha1
}
var Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
/* SHA256 Type */
type Sha256ObjectFormatImpl struct{}
var (
emptySha256ObjectID = &Sha256Hash{}
emptySha256Tree = &Sha256Hash{
0x6e, 0xf1, 0x9b, 0x41, 0x22, 0x5c, 0x53, 0x69, 0xf1, 0xc1,
0x04, 0xd4, 0x5d, 0x8d, 0x85, 0xef, 0xa9, 0xb0, 0x57, 0xb5,
0x3b, 0x14, 0xb4, 0xb9, 0xb9, 0x39, 0xdd, 0x74, 0xde, 0xcc,
0x53, 0x21,
}
)
func (Sha256ObjectFormatImpl) Name() string { return "sha256" }
func (Sha256ObjectFormatImpl) EmptyObjectID() ObjectID {
return emptySha256ObjectID
}
func (Sha256ObjectFormatImpl) EmptyTree() ObjectID {
return emptySha256Tree
}
func (Sha256ObjectFormatImpl) FullLength() int { return 64 }
func (Sha256ObjectFormatImpl) IsValid(input string) bool {
return sha256Pattern.MatchString(input)
}
func (Sha256ObjectFormatImpl) MustID(b []byte) ObjectID {
var id Sha256Hash
copy(id[0:32], b)
return &id
}
// ComputeHash compute the hash for a given ObjectType and content
func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID {
hasher := sha256.New()
_, _ = hasher.Write(t.Bytes())
_, _ = hasher.Write([]byte(" "))
_, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
_, _ = hasher.Write([]byte{0})
// HashSum generates a SHA256 for the provided hash
var sha256 Sha1Hash
copy(sha256[:], hasher.Sum(nil))
return &sha256
}
var (
Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{}
)
var SupportedObjectFormats = []ObjectFormat{
Sha1ObjectFormat,
// TODO: add sha256
}
func ObjectFormatFromName(name string) ObjectFormat {

View File

@ -16,6 +16,7 @@ type ObjectID interface {
Type() ObjectFormat
}
/* SHA1 */
type Sha1Hash [20]byte
func (h *Sha1Hash) String() string {
@ -39,6 +40,21 @@ func MustIDFromString(hexHash string) ObjectID {
return id
}
/* SHA256 */
type Sha256Hash [32]byte
func (h *Sha256Hash) String() string {
return hex.EncodeToString(h[:])
}
func (h *Sha256Hash) IsZero() bool {
empty := Sha256Hash{}
return bytes.Equal(empty[:], h[:])
}
func (h *Sha256Hash) RawValue() []byte { return h[:] }
func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat }
/* utility */
func NewIDFromString(hexHash string) (ObjectID, error) {
var theObjectFormat ObjectFormat
for _, objectFormat := range SupportedObjectFormats {

View File

@ -13,6 +13,8 @@ func ParseGogitHash(h plumbing.Hash) ObjectID {
switch hash.Size {
case 20:
return Sha1ObjectFormat.MustID(h[:])
case 32:
return Sha256ObjectFormat.MustID(h[:])
}
return nil

View File

@ -97,15 +97,14 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
}
cmd := NewCommand(ctx, "init")
if !IsValidObjectFormat(objectFormatName) {
return fmt.Errorf("invalid object format: %s", objectFormatName)
}
if SupportHashSha256 {
if objectFormatName == "" {
objectFormatName = Sha1ObjectFormat.Name()
}
if !IsValidObjectFormat(objectFormatName) {
return fmt.Errorf("invalid object format: %s", objectFormatName)
}
cmd.AddOptionValues("--object-format", objectFormatName)
}
if bare {
cmd.AddArguments("--bare")
}

View File

@ -8,6 +8,7 @@ import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
@ -62,11 +63,15 @@ func (repo *Repository) CreateArchive(ctx context.Context, format ArchiveType, t
cmd.AddOptionFormat("--format=%s", format.String())
cmd.AddDynamicArguments(commitID)
// Avoid LFS hooks getting installed because of /etc/gitconfig, which can break pull requests.
env := append(os.Environ(), "GIT_CONFIG_NOSYSTEM=1")
var stderr strings.Builder
err := cmd.Run(&RunOpts{
Dir: repo.Path,
Stdout: target,
Stderr: &stderr,
Env: env,
})
if err != nil {
return ConcatenateError(err, stderr.String())

View File

@ -3,46 +3,4 @@
package git
import (
"context"
"io"
)
// contextKey is a value for use with context.WithValue.
type contextKey struct {
name string
}
// RepositoryContextKey is a context key. It is used with context.Value() to get the current Repository for the context
var RepositoryContextKey = &contextKey{"repository"}
// RepositoryFromContext attempts to get the repository from the context
func RepositoryFromContext(ctx context.Context, path string) *Repository {
value := ctx.Value(RepositoryContextKey)
if value == nil {
return nil
}
if repo, ok := value.(*Repository); ok && repo != nil {
if repo.Path == path {
return repo
}
}
return nil
}
type nopCloser func()
func (nopCloser) Close() error { return nil }
// RepositoryFromContextOrOpen attempts to get the repository from the context or just opens it
func RepositoryFromContextOrOpen(ctx context.Context, path string) (*Repository, io.Closer, error) {
gitRepo := RepositoryFromContext(ctx, path)
if gitRepo != nil {
return gitRepo, nopCloser(nil), nil
}
gitRepo, err := OpenRepository(ctx, path)
return gitRepo, gitRepo, err
}
var isGogit bool

View File

@ -14,6 +14,7 @@ import (
gitealog "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/osfs"
gogit "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
@ -21,6 +22,10 @@ import (
"github.com/go-git/go-git/v5/storage/filesystem"
)
func init() {
isGogit = true
}
// Repository represents a Git repository.
type Repository struct {
Path string
@ -58,7 +63,15 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
return nil, err
}
}
storage := filesystem.NewStorageWithOptions(fs, cache.NewObjectLRUDefault(), filesystem.Options{KeepDescriptors: true, LargeObjectThreshold: setting.Git.LargeObjectThreshold})
// the "clone --shared" repo doesn't work well with go-git AlternativeFS, https://github.com/go-git/go-git/issues/1006
// so use "/" for AlternatesFS, I guess it is the same behavior as current nogogit (no limitation or check for the "objects/info/alternates" paths), trust the "clone" command executed by the server.
var altFs billy.Filesystem
if setting.IsWindows {
altFs = osfs.New(filepath.VolumeName(setting.RepoRootPath) + "\\") // TODO: does it really work for Windows? Need some time to check.
} else {
altFs = osfs.New("/")
}
storage := filesystem.NewStorageWithOptions(fs, cache.NewObjectLRUDefault(), filesystem.Options{KeepDescriptors: true, LargeObjectThreshold: setting.Git.LargeObjectThreshold, AlternatesFS: altFs})
gogitRepo, err := gogit.Open(storage, fs)
if err != nil {
return nil, err

View File

@ -15,6 +15,10 @@ import (
"code.gitea.io/gitea/modules/log"
)
func init() {
isGogit = false
}
// Repository represents a Git repository.
type Repository struct {
Path string

View File

@ -86,29 +86,6 @@ func (repo *Repository) GetBranch(branch string) (*Branch, error) {
}, nil
}
// GetBranchesByPath returns a branch by it's path
// if limit = 0 it will not limit
func GetBranchesByPath(ctx context.Context, path string, skip, limit int) ([]*Branch, int, error) {
gitRepo, err := OpenRepository(ctx, path)
if err != nil {
return nil, 0, err
}
defer gitRepo.Close()
return gitRepo.GetBranches(skip, limit)
}
// GetBranchCommitID returns a branch commit ID by its name
func GetBranchCommitID(ctx context.Context, path, branch string) (string, error) {
gitRepo, err := OpenRepository(ctx, path)
if err != nil {
return "", err
}
defer gitRepo.Close()
return gitRepo.GetBranchCommitID(branch)
}
// GetBranches returns a slice of *git.Branch
func (repo *Repository) GetBranches(skip, limit int) ([]*Branch, int, error) {
brs, countAll, err := repo.GetBranchNames(skip, limit)

View File

@ -7,7 +7,6 @@
package git
import (
"context"
"sort"
"strings"
@ -95,34 +94,6 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
return branchNames, len(branchData), nil
}
// WalkReferences walks all the references from the repository
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
repo := RepositoryFromContext(ctx, repoPath)
if repo == nil {
var err error
repo, err = OpenRepository(ctx, repoPath)
if err != nil {
return 0, err
}
defer repo.Close()
}
i := 0
iter, err := repo.gogitRepo.References()
if err != nil {
return i, err
}
defer iter.Close()
err = iter.ForEach(func(ref *plumbing.Reference) error {
err := walkfn(ref.Hash().String(), string(ref.Name()))
i++
return err
})
return i, err
}
// WalkReferences walks all the references from the repository
func (repo *Repository) WalkReferences(arg ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
i := 0

View File

@ -65,11 +65,6 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
return callShowRef(repo.Ctx, repo.Path, BranchPrefix, TrustedCmdArgs{BranchPrefix, "--sort=-committerdate"}, skip, limit)
}
// WalkReferences walks all the references from the repository
func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
return walkShowRef(ctx, repoPath, nil, 0, 0, walkfn)
}
// WalkReferences walks all the references from the repository
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
@ -81,12 +76,12 @@ func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walk
args = TrustedCmdArgs{BranchPrefix, "--sort=-committerdate"}
}
return walkShowRef(repo.Ctx, repo.Path, args, skip, limit, walkfn)
return WalkShowRef(repo.Ctx, repo.Path, args, skip, limit, walkfn)
}
// callShowRef return refs, if limit = 0 it will not limit
func callShowRef(ctx context.Context, repoPath, trimPrefix string, extraArgs TrustedCmdArgs, skip, limit int) (branchNames []string, countAll int, err error) {
countAll, err = walkShowRef(ctx, repoPath, extraArgs, skip, limit, func(_, branchName string) error {
countAll, err = WalkShowRef(ctx, repoPath, extraArgs, skip, limit, func(_, branchName string) error {
branchName = strings.TrimPrefix(branchName, trimPrefix)
branchNames = append(branchNames, branchName)
@ -95,7 +90,7 @@ func callShowRef(ctx context.Context, repoPath, trimPrefix string, extraArgs Tru
return branchNames, countAll, err
}
func walkShowRef(ctx context.Context, repoPath string, extraArgs TrustedCmdArgs, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
func WalkShowRef(ctx context.Context, repoPath string, extraArgs TrustedCmdArgs, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
stdoutReader, stdoutWriter := io.Pipe()
defer func() {
_ = stdoutReader.Close()
@ -189,7 +184,7 @@ func walkShowRef(ctx context.Context, repoPath string, extraArgs TrustedCmdArgs,
// GetRefsBySha returns all references filtered with prefix that belong to a sha commit hash
func (repo *Repository) GetRefsBySha(sha, prefix string) ([]string, error) {
var revList []string
_, err := walkShowRef(repo.Ctx, repo.Path, nil, 0, 0, func(walkSha, refname string) error {
_, err := WalkShowRef(repo.Ctx, repo.Path, nil, 0, 0, func(walkSha, refname string) error {
if walkSha == sha && strings.HasPrefix(refname, prefix) {
revList = append(revList, refname)
}

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