1
1
mirror of https://github.com/go-gitea/gitea synced 2024-11-11 04:34:25 +00:00

Merge branch 'main' into allow-force-push-protected-branches

This commit is contained in:
Henry Goodman 2023-12-19 20:36:12 +11:00 committed by GitHub
commit be622e5db9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
146 changed files with 907 additions and 1091 deletions

File diff suppressed because one or more lines are too long

View File

@ -16,8 +16,7 @@ var (
// CmdActions represents the available actions sub-commands. // CmdActions represents the available actions sub-commands.
CmdActions = &cli.Command{ CmdActions = &cli.Command{
Name: "actions", Name: "actions",
Usage: "", Usage: "Manage Gitea Actions",
Description: "Commands for managing Gitea Actions",
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
subcmdActionsGenRunnerToken, subcmdActionsGenRunnerToken,
}, },

View File

@ -21,7 +21,7 @@ var (
// CmdAdmin represents the available admin sub-command. // CmdAdmin represents the available admin sub-command.
CmdAdmin = &cli.Command{ CmdAdmin = &cli.Command{
Name: "admin", Name: "admin",
Usage: "Command line interface to perform common administrative operations", Usage: "Perform common administrative operations",
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
subcmdUser, subcmdUser,
subcmdRepoSyncReleases, subcmdRepoSyncReleases,

View File

@ -26,7 +26,7 @@ import (
// CmdDoctor represents the available doctor sub-command. // CmdDoctor represents the available doctor sub-command.
var CmdDoctor = &cli.Command{ var CmdDoctor = &cli.Command{
Name: "doctor", Name: "doctor",
Usage: "Diagnose and optionally fix problems", Usage: "Diagnose and optionally fix problems, convert or re-create database tables",
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.", Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{

View File

@ -18,7 +18,7 @@ var (
// CmdGenerate represents the available generate sub-command. // CmdGenerate represents the available generate sub-command.
CmdGenerate = &cli.Command{ CmdGenerate = &cli.Command{
Name: "generate", Name: "generate",
Usage: "Command line interface for running generators", Usage: "Generate Gitea's secrets/keys/tokens",
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
subcmdSecret, subcmdSecret,
}, },

View File

@ -31,8 +31,8 @@ var (
// CmdHook represents the available hooks sub-command. // CmdHook represents the available hooks sub-command.
CmdHook = &cli.Command{ CmdHook = &cli.Command{
Name: "hook", Name: "hook",
Usage: "Delegate commands to corresponding Git hooks", Usage: "(internal) Should only be called by Git",
Description: "This should only be called by Git", Description: "Delegate commands to corresponding Git hooks",
Before: PrepareConsoleLoggerLevel(log.FATAL), Before: PrepareConsoleLoggerLevel(log.FATAL),
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
subcmdHookPreReceive, subcmdHookPreReceive,
@ -377,7 +377,7 @@ Gitea or set your environment appropriately.`, "")
newCommitIDs[count] = string(fields[1]) newCommitIDs[count] = string(fields[1])
refFullNames[count] = git.RefName(fields[2]) refFullNames[count] = git.RefName(fields[2])
commitID, _ := git.IDFromString(newCommitIDs[count]) commitID, _ := git.NewIDFromString(newCommitIDs[count])
if refFullNames[count] == git.BranchPrefix+"master" && !commitID.IsZero() && count == total { if refFullNames[count] == git.BranchPrefix+"master" && !commitID.IsZero() && count == total {
masterPushed = true masterPushed = true
} }
@ -671,7 +671,7 @@ Gitea or set your environment appropriately.`, "")
if err != nil { if err != nil {
return err return err
} }
commitID, _ := git.IDFromString(rs.OldOID) commitID, _ := git.NewIDFromString(rs.OldOID)
if !commitID.IsZero() { if !commitID.IsZero() {
err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID)) err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
if err != nil { if err != nil {

View File

@ -17,7 +17,8 @@ import (
// CmdKeys represents the available keys sub-command // CmdKeys represents the available keys sub-command
var CmdKeys = &cli.Command{ var CmdKeys = &cli.Command{
Name: "keys", Name: "keys",
Usage: "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint", Usage: "(internal) Should only be called by SSH server",
Description: "Queries the Gitea database to get the authorized command for a given ssh key fingerprint",
Before: PrepareConsoleLoggerLevel(log.FATAL), Before: PrepareConsoleLoggerLevel(log.FATAL),
Action: runKeys, Action: runKeys,
Flags: []cli.Flag{ Flags: []cli.Flag{

View File

@ -10,12 +10,12 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
// cmdHelp is our own help subcommand with more information // cmdHelp is our own help subcommand with more information
// Keep in mind that the "./gitea help"(subcommand) is different from "./gitea --help"(flag), the flag doesn't parse the config or output "DEFAULT CONFIGURATION:" information
func cmdHelp() *cli.Command { func cmdHelp() *cli.Command {
c := &cli.Command{ c := &cli.Command{
Name: "help", Name: "help",
@ -47,16 +47,10 @@ DEFAULT CONFIGURATION:
return c return c
} }
var helpFlag = cli.HelpFlag
func init() {
// cli.HelpFlag = nil TODO: after https://github.com/urfave/cli/issues/1794 we can use this
}
func appGlobalFlags() []cli.Flag { func appGlobalFlags() []cli.Flag {
return []cli.Flag{ return []cli.Flag{
// make the builtin flags at the top // make the builtin flags at the top
helpFlag, cli.HelpFlag,
// shared configuration flags, they are for global and for each sub-command at the same time // shared configuration flags, they are for global and for each sub-command at the same time
// eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed // eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
@ -121,20 +115,22 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context)
func NewMainApp(version, versionExtra string) *cli.App { func NewMainApp(version, versionExtra string) *cli.App {
app := cli.NewApp() app := cli.NewApp()
app.Name = "Gitea" app.Name = "Gitea"
app.HelpName = "gitea"
app.Usage = "A painless self-hosted Git service" app.Usage = "A painless self-hosted Git service"
app.Description = `By default, Gitea will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".` app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
app.Version = version + versionExtra app.Version = version + versionExtra
app.EnableBashCompletion = true app.EnableBashCompletion = true
// these sub-commands need to use config file // these sub-commands need to use config file
subCmdWithConfig := []*cli.Command{ subCmdWithConfig := []*cli.Command{
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
CmdWeb, CmdWeb,
CmdServ, CmdServ,
CmdHook, CmdHook,
CmdKeys,
CmdDump, CmdDump,
CmdAdmin, CmdAdmin,
CmdMigrate, CmdMigrate,
CmdKeys,
CmdDoctor, CmdDoctor,
CmdManager, CmdManager,
CmdEmbedded, CmdEmbedded,
@ -142,13 +138,8 @@ func NewMainApp(version, versionExtra string) *cli.App {
CmdDumpRepository, CmdDumpRepository,
CmdRestoreRepository, CmdRestoreRepository,
CmdActions, CmdActions,
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
} }
cmdConvert := util.ToPointer(*cmdDoctorConvert)
cmdConvert.Hidden = true // still support the legacy "./gitea doctor" by the hidden sub-command, remove it in next release
subCmdWithConfig = append(subCmdWithConfig, cmdConvert)
// these sub-commands do not need the config file, and they do not depend on any path or environment variable. // these sub-commands do not need the config file, and they do not depend on any path or environment variable.
subCmdStandalone := []*cli.Command{ subCmdStandalone := []*cli.Command{
CmdCert, CmdCert,

View File

@ -42,7 +42,7 @@ const (
// CmdServ represents the available serv sub-command. // CmdServ represents the available serv sub-command.
var CmdServ = &cli.Command{ var CmdServ = &cli.Command{
Name: "serv", Name: "serv",
Usage: "This command should only be called by SSH shell", Usage: "(internal) Should only be called by SSH shell",
Description: "Serv provides access auth for repositories", Description: "Serv provides access auth for repositories",
Before: PrepareConsoleLoggerLevel(log.FATAL), Before: PrepareConsoleLoggerLevel(log.FATAL),
Action: runServ, Action: runServ,

View File

@ -17,7 +17,7 @@ import (
"strings" "strings"
"syscall" "syscall"
"github.com/google/go-github/v53/github" "github.com/google/go-github/v57/github"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )

View File

@ -1212,6 +1212,9 @@ LEVEL = Info
;; Max size of files to be displayed (default is 8MiB) ;; Max size of files to be displayed (default is 8MiB)
;MAX_DISPLAY_FILE_SIZE = 8388608 ;MAX_DISPLAY_FILE_SIZE = 8388608
;; ;;
;; Detect ambiguous unicode characters in file contents and show warnings on the UI
;AMBIGUOUS_UNICODE_DETECTION = true
;;
;; Whether the email of the user should be shown in the Explore Users page ;; Whether the email of the user should be shown in the Explore Users page
;SHOW_USER_EMAIL = true ;SHOW_USER_EMAIL = true
;; ;;
@ -1702,9 +1705,6 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; if the cache enabled
;ENABLED = true
;;
;; Either "memory", "redis", "memcache", or "twoqueue". default is "memory" ;; Either "memory", "redis", "memcache", or "twoqueue". default is "memory"
;ADAPTER = memory ;ADAPTER = memory
;; ;;
@ -1729,8 +1729,6 @@ LEVEL = Info
;[cache.last_commit] ;[cache.last_commit]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; if the cache enabled
;ENABLED = true
;; ;;
;; Time to keep items in cache if not used, default is 8760 hours. ;; Time to keep items in cache if not used, default is 8760 hours.
;; Setting it to -1 disables caching ;; Setting it to -1 disables caching

View File

@ -220,6 +220,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes. - `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes.
regardless of the value of `DEFAULT_THEME`. regardless of the value of `DEFAULT_THEME`.
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB) - `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB)
- `AMBIGUOUS_UNICODE_DETECTION`: **true**: Detect ambiguous unicode characters in file contents and show warnings on the UI
- `REACTIONS`: All available reactions users can choose on issues/prs and comments - `REACTIONS`: All available reactions users can choose on issues/prs and comments
Values can be emoji alias (:smile:) or a unicode emoji. Values can be emoji alias (:smile:) or a unicode emoji.
For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png
@ -572,6 +573,7 @@ And the following unique queues:
- off - do not check password complexity - off - do not check password complexity
- `PASSWORD_CHECK_PWN`: **false**: Check [HaveIBeenPwned](https://haveibeenpwned.com/Passwords) to see if a password has been exposed. - `PASSWORD_CHECK_PWN`: **false**: Check [HaveIBeenPwned](https://haveibeenpwned.com/Passwords) to see if a password has been exposed.
- `SUCCESSFUL_TOKENS_CACHE_SIZE`: **20**: Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations. This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security. - `SUCCESSFUL_TOKENS_CACHE_SIZE`: **20**: Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations. This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
- `DISABLE_QUERY_AUTH_TOKEN`: **false**: Reject API tokens sent in URL query string (Accept Header-based API tokens only). This setting will default to `true` in Gitea 1.23 and be deprecated in Gitea 1.24.
## Camo (`camo`) ## Camo (`camo`)
@ -761,7 +763,6 @@ and
## Cache (`cache`) ## Cache (`cache`)
- `ENABLED`: **true**: Enable the cache.
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `redis-cluster`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.) - `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `redis-cluster`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.)
- `INTERVAL`: **60**: Garbage Collection interval (sec), for memory and twoqueue cache only. - `INTERVAL`: **60**: Garbage Collection interval (sec), for memory and twoqueue cache only.
- `HOST`: **_empty_**: Connection string for `redis`, `redis-cluster` and `memcache`. For `twoqueue` sets configuration for the queue. - `HOST`: **_empty_**: Connection string for `redis`, `redis-cluster` and `memcache`. For `twoqueue` sets configuration for the queue.
@ -773,7 +774,6 @@ and
## Cache - LastCommitCache settings (`cache.last_commit`) ## Cache - LastCommitCache settings (`cache.last_commit`)
- `ENABLED`: **true**: Enable the cache.
- `ITEM_TTL`: **8760h**: Time to keep items in cache if not used, Setting it to -1 disables caching. - `ITEM_TTL`: **8760h**: Time to keep items in cache if not used, Setting it to -1 disables caching.
- `COMMITS_COUNT`: **1000**: Only enable the cache when repository's commits count great than. - `COMMITS_COUNT`: **1000**: Only enable the cache when repository's commits count great than.

View File

@ -721,7 +721,6 @@ Gitea 创建以下非唯一队列:
## 缓存 (`cache`) ## 缓存 (`cache`)
- `ENABLED`: **true**: 是否启用缓存。
- `ADAPTER`: **memory**: 缓存引擎,可以为 `memory`, `redis`, `redis-cluster`, `twoqueue``memcache`. (`twoqueue` 代表缓冲区固定的LRU缓存) - `ADAPTER`: **memory**: 缓存引擎,可以为 `memory`, `redis`, `redis-cluster`, `twoqueue``memcache`. (`twoqueue` 代表缓冲区固定的LRU缓存)
- `INTERVAL`: **60**: 垃圾回收间隔(秒),只对`memory`和`towqueue`有效。 - `INTERVAL`: **60**: 垃圾回收间隔(秒),只对`memory`和`towqueue`有效。
- `HOST`: **_empty_**: 缓存配置。`redis`, `redis-cluster``memcache`配置连接字符串;`twoqueue` 设置队列参数 - `HOST`: **_empty_**: 缓存配置。`redis`, `redis-cluster``memcache`配置连接字符串;`twoqueue` 设置队列参数
@ -733,7 +732,6 @@ Gitea 创建以下非唯一队列:
### 缓存 - 最后提交缓存设置 (`cache.last_commit`) ### 缓存 - 最后提交缓存设置 (`cache.last_commit`)
- `ENABLED`: **true**:是否启用缓存。
- `ITEM_TTL`: **8760h**:如果未使用,保持缓存中的项目的时间,将其设置为 -1 会禁用缓存。 - `ITEM_TTL`: **8760h**:如果未使用,保持缓存中的项目的时间,将其设置为 -1 会禁用缓存。
- `COMMITS_COUNT`: **1000**:仅在存储库的提交计数大于时启用缓存。 - `COMMITS_COUNT`: **1000**:仅在存储库的提交计数大于时启用缓存。
@ -1039,10 +1037,11 @@ Gitea 创建以下非唯一队列:
## API (`api`) ## API (`api`)
- `ENABLE_SWAGGER`: **true**: 是否启用swagger路由 (`/api/swagger`, `/api/v1/swagger`, …)。 - `ENABLE_SWAGGER`: **true**: 启用API文档接口 (`/api/swagger`, `/api/v1/swagger`, …). True or false。
- `MAX_RESPONSE_ITEMS`: **50**: 单个页面的最大 Feed. - `MAX_RESPONSE_ITEMS`: **50**: API分页的最大单页项目数。
- `ENABLE_OPENID_SIGNIN`: **false**: 允许使用OpenID登录当设置为`true`时可以通过 `/user/login` 页面进行OpenID登录。 - `DEFAULT_PAGING_NUM`: **30**: API分页的默认分页数。
- `DISABLE_REGISTRATION`: **false**: 关闭用户注册。 - `DEFAULT_GIT_TREES_PER_PAGE`: **1000**: Git trees API的默认单页项目数。
- `DEFAULT_MAX_BLOB_SIZE`: **10485760** (10MiB): blobs API的默认最大文件大小。
## OAuth2 (`oauth2`) ## OAuth2 (`oauth2`)

View File

@ -362,7 +362,7 @@ If you are receiving errors on upgrade of Gitea using MySQL that read:
> `ORM engine initialization failed: migrate: do migrate: Error: 1118: Row size too large...` > `ORM engine initialization failed: migrate: do migrate: Error: 1118: Row size too large...`
Please run `gitea convert` or run `ALTER TABLE table_name ROW_FORMAT=dynamic;` for each table in the database. Please run `gitea doctor convert` or run `ALTER TABLE table_name ROW_FORMAT=dynamic;` for each table in the database.
The underlying problem is that the space allocated for indices by the default row format The underlying problem is that the space allocated for indices by the default row format
is too small. Gitea requires that the `ROWFORMAT` for its tables is `DYNAMIC`. is too small. Gitea requires that the `ROWFORMAT` for its tables is `DYNAMIC`.
@ -385,7 +385,7 @@ Unfortunately MySQL's `utf8` charset does not completely allow all possible UTF-
They created a new charset and collation called `utf8mb4` that allows for emoji to be stored but tables which use They created a new charset and collation called `utf8mb4` that allows for emoji to be stored but tables which use
the `utf8` charset, and connections which use the `utf8` charset will not use this. the `utf8` charset, and connections which use the `utf8` charset will not use this.
Please run `gitea convert`, or run `ALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;` Please run `gitea doctor convert`, or run `ALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
for the database_name and run `ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;` for the database_name and run `ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
for each table in the database. for each table in the database.

View File

@ -366,7 +366,7 @@ Gitea 提供了一个子命令`gitea migrate`来初始化数据库,然后您
> `ORM engine initialization failed: migrate: do migrate: Error: 1118: Row size too large...` > `ORM engine initialization failed: migrate: do migrate: Error: 1118: Row size too large...`
请运行`gitea convert`或对数据库中的每个表运行`ALTER TABLE table_name ROW_FORMAT=dynamic;`。 请运行 `gitea doctor convert` 或对数据库中的每个表运行 `ALTER TABLE table_name ROW_FORMAT=dynamic;`
潜在问题是默认行格式分配给每个表的索引空间 潜在问题是默认行格式分配给每个表的索引空间
太小。Gitea 要求其表的`ROWFORMAT`为`DYNAMIC`。 太小。Gitea 要求其表的`ROWFORMAT`为`DYNAMIC`。
@ -389,9 +389,8 @@ SET GLOBAL innodb_large_prefix=1;
他们创建了一个名为 `utf8mb4`的字符集和校对规则,允许存储 Emoji但使用 他们创建了一个名为 `utf8mb4`的字符集和校对规则,允许存储 Emoji但使用
utf8 字符集的表和连接将不会使用它。 utf8 字符集的表和连接将不会使用它。
请运行 `gitea convert` 或对数据库运行`ALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;` 请运行 `gitea doctor convert` 或对数据库运行 `ALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
并对每个表运行 并对每个表运行 `ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
`ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
您还需要将`app.ini`文件中的数据库字符集设置为`CHARSET=utf8mb4`。 您还需要将`app.ini`文件中的数据库字符集设置为`CHARSET=utf8mb4`。

168
go.mod
View File

@ -5,7 +5,7 @@ go 1.21
require ( require (
code.gitea.io/actions-proto-go v0.3.1 code.gitea.io/actions-proto-go v0.3.1
code.gitea.io/gitea-vet v0.2.3 code.gitea.io/gitea-vet v0.2.3
code.gitea.io/sdk/gitea v0.16.0 code.gitea.io/sdk/gitea v0.17.0
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669 gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669
gitea.com/go-chi/cache v0.2.0 gitea.com/go-chi/cache v0.2.0
@ -17,12 +17,12 @@ require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
github.com/NYTimes/gziphandler v1.1.1 github.com/NYTimes/gziphandler v1.1.1
github.com/PuerkitoBio/goquery v1.8.1 github.com/PuerkitoBio/goquery v1.8.1
github.com/alecthomas/chroma/v2 v2.10.0 github.com/alecthomas/chroma/v2 v2.12.0
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.3.10 github.com/blevesearch/bleve/v2 v2.3.10
github.com/bufbuild/connect-go v1.10.0 github.com/bufbuild/connect-go v1.10.0
github.com/buildkite/terminal-to-html/v3 v3.9.1 github.com/buildkite/terminal-to-html/v3 v3.10.0
github.com/caddyserver/certmagic v0.19.2 github.com/caddyserver/certmagic v0.20.0
github.com/chi-middleware/proxy v1.1.1 github.com/chi-middleware/proxy v1.1.1
github.com/denisenkom/go-mssqldb v0.12.3 github.com/denisenkom/go-mssqldb v0.12.3
github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21 github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21
@ -35,13 +35,13 @@ require (
github.com/emirpasic/gods v1.18.1 github.com/emirpasic/gods v1.18.1
github.com/ethantkoenig/rupture v1.0.1 github.com/ethantkoenig/rupture v1.0.1
github.com/felixge/fgprof v0.9.3 github.com/felixge/fgprof v0.9.3
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.7.0
github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46 github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46
github.com/go-ap/activitypub v0.0.0-20231003111253-1fba3772399b github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 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.10
github.com/go-chi/cors v1.2.1 github.com/go-chi/cors v1.2.1
github.com/go-co-op/gocron v1.31.1 github.com/go-co-op/gocron v1.37.0
github.com/go-enry/go-enry/v2 v2.8.6 github.com/go-enry/go-enry/v2 v2.8.6
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e 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-billy/v5 v5.5.0
@ -50,34 +50,34 @@ require (
github.com/go-sql-driver/mysql v1.7.1 github.com/go-sql-driver/mysql v1.7.1
github.com/go-swagger/go-swagger v0.30.5 github.com/go-swagger/go-swagger v0.30.5
github.com/go-testfixtures/testfixtures/v3 v3.9.0 github.com/go-testfixtures/testfixtures/v3 v3.9.0
github.com/go-webauthn/webauthn v0.8.6 github.com/go-webauthn/webauthn v0.9.4
github.com/gobwas/glob v0.2.3 github.com/gobwas/glob v0.2.3
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v5 v5.0.0 github.com/golang-jwt/jwt/v5 v5.2.0
github.com/google/go-github/v53 v53.2.0 github.com/google/go-github/v57 v57.0.0
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 github.com/google/pprof v0.0.0-20231212022811-ec68065c825e
github.com/google/uuid v1.3.1 github.com/google/uuid v1.5.0
github.com/gorilla/feeds v1.1.1 github.com/gorilla/feeds v1.1.2
github.com/gorilla/sessions v1.2.1 github.com/gorilla/sessions v1.2.2
github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/huandu/xstrings v1.4.0 github.com/huandu/xstrings v1.4.0
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056
github.com/jhillyerd/enmime v1.0.1 github.com/jhillyerd/enmime v1.1.0
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
github.com/klauspost/compress v1.17.0 github.com/klauspost/compress v1.17.4
github.com/klauspost/cpuid/v2 v2.2.5 github.com/klauspost/cpuid/v2 v2.2.6
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.9
github.com/markbates/goth v1.78.0 github.com/markbates/goth v1.78.0
github.com/mattn/go-isatty v0.0.19 github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-sqlite3 v1.14.17 github.com/mattn/go-sqlite3 v1.14.19
github.com/meilisearch/meilisearch-go v0.25.1 github.com/meilisearch/meilisearch-go v0.26.0
github.com/mholt/archiver/v3 v3.5.1 github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.26 github.com/microcosm-cc/bluemonday v1.0.26
github.com/minio/minio-go/v7 v7.0.63 github.com/minio/minio-go/v7 v7.0.66
github.com/minio/sha256-simd v1.0.1 github.com/minio/sha256-simd v1.0.1
github.com/msteinert/pam v1.2.0 github.com/msteinert/pam v1.2.0
github.com/nektos/act v0.2.52 github.com/nektos/act v0.2.52
@ -89,7 +89,7 @@ require (
github.com/pquerna/otp v1.4.0 github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_golang v1.17.0
github.com/quasoft/websspi v1.1.2 github.com/quasoft/websspi v1.1.2
github.com/redis/go-redis/v9 v9.2.1 github.com/redis/go-redis/v9 v9.3.0
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/santhosh-tekuri/jsonschema/v5 v5.3.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.0
@ -99,21 +99,21 @@ require (
github.com/syndtr/goleveldb v1.0.0 github.com/syndtr/goleveldb v1.0.0
github.com/tstranex/u2f v1.0.0 github.com/tstranex/u2f v1.0.0
github.com/ulikunitz/xz v0.5.11 github.com/ulikunitz/xz v0.5.11
github.com/urfave/cli/v2 v2.25.7 github.com/urfave/cli/v2 v2.26.0
github.com/xanzy/go-gitlab v0.93.1 github.com/xanzy/go-gitlab v0.95.2
github.com/xeipuuv/gojsonschema v1.2.0 github.com/xeipuuv/gojsonschema v1.2.0
github.com/yohcop/openid-go v1.0.1 github.com/yohcop/openid-go v1.0.1
github.com/yuin/goldmark v1.5.6 github.com/yuin/goldmark v1.6.0
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
github.com/yuin/goldmark-meta v1.1.0 github.com/yuin/goldmark-meta v1.1.0
golang.org/x/crypto v0.14.0 golang.org/x/crypto v0.17.0
golang.org/x/image v0.13.0 golang.org/x/image v0.14.0
golang.org/x/net v0.17.0 golang.org/x/net v0.19.0
golang.org/x/oauth2 v0.13.0 golang.org/x/oauth2 v0.15.0
golang.org/x/sys v0.13.0 golang.org/x/sys v0.15.0
golang.org/x/text v0.13.0 golang.org/x/text v0.14.0
golang.org/x/tools v0.14.0 golang.org/x/tools v0.16.1
google.golang.org/grpc v1.58.3 google.golang.org/grpc v1.60.0
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.67.0 gopkg.in/ini.v1 v1.67.0
@ -125,33 +125,33 @@ require (
) )
require ( require (
cloud.google.com/go/compute v1.23.1 // indirect cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect
dario.cat/mergo v1.0.0 // indirect dario.cat/mergo v1.0.0 // indirect
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
github.com/ClickHouse/ch-go v0.58.2 // indirect github.com/ClickHouse/ch-go v0.61.0 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.14.3 // indirect github.com/ClickHouse/clickhouse-go/v2 v2.16.0 // indirect
github.com/DataDog/zstd v1.5.5 // indirect github.com/DataDog/zstd v1.5.5 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.1 // 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 v0.0.0-20230923063757-afb1ddc0824c // indirect
github.com/RoaringBitmap/roaring v1.6.0 // indirect github.com/RoaringBitmap/roaring v1.7.0 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.6 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aymerick/douceur v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.9.0 // indirect github.com/bits-and-blooms/bitset v1.12.0 // indirect
github.com/blevesearch/bleve_index_api v1.0.6 // indirect github.com/blevesearch/bleve_index_api v1.1.4 // indirect
github.com/blevesearch/geo v0.1.18 // indirect github.com/blevesearch/geo v0.1.18 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
github.com/blevesearch/gtreap v0.1.1 // indirect github.com/blevesearch/gtreap v0.1.1 // indirect
github.com/blevesearch/mmap-go v1.0.4 // indirect github.com/blevesearch/mmap-go v1.0.4 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.1.6 // indirect github.com/blevesearch/scorch_segment_api/v2 v2.2.5 // indirect
github.com/blevesearch/segment v0.9.1 // indirect github.com/blevesearch/segment v0.9.1 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
@ -165,9 +165,9 @@ require (
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudflare/circl v1.3.3 // indirect github.com/cloudflare/circl v1.3.6 // indirect
github.com/couchbase/go-couchbase v0.1.1 // indirect github.com/couchbase/go-couchbase v0.1.1 // indirect
github.com/couchbase/gomemcached v0.2.1 // indirect github.com/couchbase/gomemcached v0.3.0 // indirect
github.com/couchbase/goutils v0.1.2 // indirect github.com/couchbase/goutils v0.1.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect
@ -175,28 +175,28 @@ require (
github.com/davidmz/go-pageant v1.0.2 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead // indirect github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect
github.com/fatih/color v1.15.0 // indirect github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
github.com/go-enry/go-oniguruma v1.2.1 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect
github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/city v1.0.1 // indirect
github.com/go-faster/errors v0.6.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-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/analysis v0.21.5 // indirect
github.com/go-openapi/errors v0.20.4 // indirect github.com/go-openapi/errors v0.21.0 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect github.com/go-openapi/jsonpointer v0.20.1 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.3 // indirect
github.com/go-openapi/loads v0.21.2 // indirect github.com/go-openapi/loads v0.21.3 // indirect
github.com/go-openapi/runtime v0.26.0 // indirect github.com/go-openapi/runtime v0.26.2 // indirect
github.com/go-openapi/spec v0.20.9 // indirect github.com/go-openapi/spec v0.20.12 // indirect
github.com/go-openapi/strfmt v0.21.7 // indirect github.com/go-openapi/strfmt v0.21.10 // indirect
github.com/go-openapi/swag v0.22.4 // indirect github.com/go-openapi/swag v0.22.5 // indirect
github.com/go-openapi/validate v0.22.1 // indirect github.com/go-openapi/validate v0.22.4 // indirect
github.com/go-webauthn/x v0.1.4 // indirect github.com/go-webauthn/x v0.1.5 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
@ -207,12 +207,12 @@ require (
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-tpm v0.9.0 // indirect github.com/google/go-tpm v0.9.0 // indirect
github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/css v1.0.1 // indirect
github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect github.com/imdario/mergo v0.3.16 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
@ -228,9 +228,9 @@ require (
github.com/markbates/going v1.0.3 // indirect github.com/markbates/going v1.0.3 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mholt/acmez v1.2.0 // indirect github.com/mholt/acmez v1.2.0 // indirect
github.com/miekg/dns v1.1.56 // indirect github.com/miekg/dns v1.1.57 // indirect
github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/md5-simd v1.1.2 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
@ -244,19 +244,19 @@ require (
github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect
github.com/paulmach/orb v0.10.0 // indirect github.com/paulmach/orb v0.10.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pierrec/lz4/v4 v4.1.19 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // 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/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/rhysd/actionlint v1.6.26 // indirect github.com/rhysd/actionlint v1.6.26 // indirect
github.com/rivo/uniseg v0.4.4 // indirect github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rs/xid v1.5.0 // indirect github.com/rs/xid v1.5.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect github.com/segmentio/asm v1.2.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect github.com/shopspring/decimal v1.3.1 // indirect
@ -264,37 +264,37 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect github.com/skeema/knownhosts v1.2.1 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.10.0 // indirect github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.5.1 // indirect github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.17.0 // indirect github.com/spf13/viper v1.18.2 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/toqueteos/webbrowser v1.2.0 // indirect github.com/toqueteos/webbrowser v1.2.0 // indirect
github.com/unknwon/com v1.0.1 // indirect github.com/unknwon/com v1.0.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.50.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect
github.com/valyala/fastjson v1.6.4 // indirect github.com/valyala/fastjson v1.6.4 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
github.com/zeebo/blake3 v0.2.3 // indirect github.com/zeebo/blake3 v0.2.3 // indirect
go.etcd.io/bbolt v1.3.7 // indirect go.etcd.io/bbolt v1.3.8 // indirect
go.mongodb.org/mongo-driver v1.12.1 // indirect go.mongodb.org/mongo-driver v1.13.1 // indirect
go.opentelemetry.io/otel v1.19.0 // indirect go.opentelemetry.io/otel v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.19.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect go.uber.org/zap v1.26.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect
golang.org/x/mod v0.13.0 // indirect golang.org/x/mod v0.14.0 // indirect
golang.org/x/sync v0.4.0 // indirect golang.org/x/sync v0.5.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.5.0 // indirect
google.golang.org/appengine v1.6.8 // indirect google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect

488
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,11 @@ type ActionRunner struct {
Deleted timeutil.TimeStamp `xorm:"deleted"` Deleted timeutil.TimeStamp `xorm:"deleted"`
} }
const (
RunnerOfflineTime = time.Minute
RunnerIdleTime = 10 * time.Second
)
// BelongsToOwnerName before calling, should guarantee that all attributes are loaded // BelongsToOwnerName before calling, should guarantee that all attributes are loaded
func (r *ActionRunner) BelongsToOwnerName() string { func (r *ActionRunner) BelongsToOwnerName() string {
if r.RepoID != 0 { if r.RepoID != 0 {
@ -76,11 +81,12 @@ func (r *ActionRunner) BelongsToOwnerType() types.OwnerType {
return types.OwnerTypeSystemGlobal return types.OwnerTypeSystemGlobal
} }
// if the logic here changed, you should also modify FindRunnerOptions.ToCond
func (r *ActionRunner) Status() runnerv1.RunnerStatus { func (r *ActionRunner) Status() runnerv1.RunnerStatus {
if time.Since(r.LastOnline.AsTime()) > time.Minute { if time.Since(r.LastOnline.AsTime()) > RunnerOfflineTime {
return runnerv1.RunnerStatus_RUNNER_STATUS_OFFLINE return runnerv1.RunnerStatus_RUNNER_STATUS_OFFLINE
} }
if time.Since(r.LastActive.AsTime()) > 10*time.Second { if time.Since(r.LastActive.AsTime()) > RunnerIdleTime {
return runnerv1.RunnerStatus_RUNNER_STATUS_IDLE return runnerv1.RunnerStatus_RUNNER_STATUS_IDLE
} }
return runnerv1.RunnerStatus_RUNNER_STATUS_ACTIVE return runnerv1.RunnerStatus_RUNNER_STATUS_ACTIVE
@ -153,6 +159,7 @@ type FindRunnerOptions struct {
OwnerID int64 OwnerID int64
Sort string Sort string
Filter string Filter string
IsOnline util.OptionalBool
WithAvailable bool // not only runners belong to, but also runners can be used WithAvailable bool // not only runners belong to, but also runners can be used
} }
@ -178,6 +185,12 @@ func (opts FindRunnerOptions) ToConds() builder.Cond {
if opts.Filter != "" { if opts.Filter != "" {
cond = cond.And(builder.Like{"name", opts.Filter}) cond = cond.And(builder.Like{"name", opts.Filter})
} }
if opts.IsOnline.IsTrue() {
cond = cond.And(builder.Gt{"last_online": time.Now().Add(-RunnerOfflineTime).Unix()})
} else if opts.IsOnline.IsFalse() {
cond = cond.And(builder.Lte{"last_online": time.Now().Add(-RunnerOfflineTime).Unix()})
}
return cond return cond
} }

View File

@ -20,6 +20,7 @@ import (
func TestAddDeletedBranch(t *testing.T) { func TestAddDeletedBranch(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
assert.EqualValues(t, git.Sha1ObjectFormat.Name(), repo.ObjectFormatName)
firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1}) firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1})
assert.True(t, firstBranch.IsDeleted) assert.True(t, firstBranch.IsDeleted)
@ -30,7 +31,7 @@ func TestAddDeletedBranch(t *testing.T) {
assert.True(t, secondBranch.IsDeleted) assert.True(t, secondBranch.IsDeleted)
commit := &git.Commit{ commit := &git.Commit{
ID: repo.ObjectFormat.MustIDFromString(secondBranch.CommitID), ID: git.MustIDFromString(secondBranch.CommitID),
CommitMessage: secondBranch.CommitMessage, CommitMessage: secondBranch.CommitMessage,
Committer: &git.Signature{ Committer: &git.Signature{
When: secondBranch.CommitTime.AsLocalTime(), When: secondBranch.CommitTime.AsLocalTime(),

View File

@ -114,7 +114,7 @@ WHEN NOT MATCHED
// GetNextCommitStatusIndex retried 3 times to generate a resource index // GetNextCommitStatusIndex retried 3 times to generate a resource index
func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) {
_, err := git.IDFromString(sha) _, err := git.NewIDFromString(sha)
if err != nil { if err != nil {
return 0, git.ErrInvalidSHA{SHA: sha} return 0, git.ErrInvalidSHA{SHA: sha}
} }

View File

@ -180,7 +180,7 @@ type Repository struct {
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"` IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"` CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
Topics []string `xorm:"TEXT JSON"` Topics []string `xorm:"TEXT JSON"`
ObjectFormat git.ObjectFormat `xorm:"-"` ObjectFormatName string `xorm:"-"`
TrustModel TrustModelType TrustModel TrustModelType
@ -277,7 +277,9 @@ func (repo *Repository) AfterLoad() {
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns
repo.ObjectFormat = git.ObjectFormatFromID(git.Sha1) // 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. // LoadAttributes loads attributes of the repository.
@ -606,25 +608,23 @@ func ComposeHTTPSCloneURL(owner, repo string) string {
func ComposeSSHCloneURL(ownerName, repoName string) string { func ComposeSSHCloneURL(ownerName, repoName string) string {
sshUser := setting.SSH.User sshUser := setting.SSH.User
// if we have a ipv6 literal we need to put brackets around it
// for the git cloning to work.
sshDomain := setting.SSH.Domain sshDomain := setting.SSH.Domain
ip := net.ParseIP(setting.SSH.Domain)
if ip != nil && ip.To4() == nil { // non-standard port, it must use full URI
sshDomain = "[" + setting.SSH.Domain + "]" if setting.SSH.Port != 22 {
sshHost := net.JoinHostPort(sshDomain, strconv.Itoa(setting.SSH.Port))
return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
} }
if setting.SSH.Port != 22 { // for standard port, it can use a shorter URI (without the port)
return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshHost := sshDomain
net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)), if ip := net.ParseIP(sshHost); ip != nil && ip.To4() == nil {
url.PathEscape(ownerName), sshHost = "[" + sshHost + "]" // for IPv6 address, wrap it with brackets
url.PathEscape(repoName))
} }
if setting.Repository.UseCompatSSHURI { if setting.Repository.UseCompatSSHURI {
return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, url.PathEscape(ownerName), url.PathEscape(repoName)) return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
} }
return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, url.PathEscape(ownerName), url.PathEscape(repoName)) return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
} }
func (repo *Repository) cloneLink(isWiki bool) *CloneLink { func (repo *Repository) cloneLink(isWiki bool) *CloneLink {

View File

@ -12,6 +12,8 @@ import (
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -186,3 +188,32 @@ func TestGetRepositoryByURL(t *testing.T) {
test(t, "try.gitea.io:user2/repo2.git") test(t, "try.gitea.io:user2/repo2.git")
}) })
} }
func TestComposeSSHCloneURL(t *testing.T) {
defer test.MockVariableValue(&setting.SSH, setting.SSH)()
defer test.MockVariableValue(&setting.Repository, setting.Repository)()
setting.SSH.User = "git"
// test SSH_DOMAIN
setting.SSH.Domain = "domain"
setting.SSH.Port = 22
setting.Repository.UseCompatSSHURI = false
assert.Equal(t, "git@domain:user/repo.git", repo_model.ComposeSSHCloneURL("user", "repo"))
setting.Repository.UseCompatSSHURI = true
assert.Equal(t, "ssh://git@domain/user/repo.git", repo_model.ComposeSSHCloneURL("user", "repo"))
// test SSH_DOMAIN while use non-standard SSH port
setting.SSH.Port = 123
setting.Repository.UseCompatSSHURI = false
assert.Equal(t, "ssh://git@domain:123/user/repo.git", repo_model.ComposeSSHCloneURL("user", "repo"))
setting.Repository.UseCompatSSHURI = true
assert.Equal(t, "ssh://git@domain:123/user/repo.git", repo_model.ComposeSSHCloneURL("user", "repo"))
// test IPv6 SSH_DOMAIN
setting.Repository.UseCompatSSHURI = false
setting.SSH.Domain = "::1"
setting.SSH.Port = 22
assert.Equal(t, "git@[::1]:user/repo.git", repo_model.ComposeSSHCloneURL("user", "repo"))
setting.SSH.Port = 123
assert.Equal(t, "ssh://git@[::1]:123/user/repo.git", repo_model.ComposeSSHCloneURL("user", "repo"))
}

View File

@ -377,3 +377,13 @@ func syncTopicsInRepository(sess db.Engine, repoID int64) error {
} }
return nil return nil
} }
// CountOrphanedAttachments returns the number of topics that don't belong to any repository.
func CountOrphanedTopics(ctx context.Context) (int64, error) {
return db.GetEngine(ctx).Where("repo_count = 0").Count(new(Topic))
}
// DeleteOrphanedAttachments delete all topics that don't belong to any repository.
func DeleteOrphanedTopics(ctx context.Context) (int64, error) {
return db.GetEngine(ctx).Where("repo_count = 0").Delete(new(Topic))
}

View File

@ -24,11 +24,11 @@ func newCache(cacheConfig setting.Cache) (mc.Cache, error) {
}) })
} }
// NewContext start cache service // Init start cache service
func NewContext() error { func Init() error {
var err error var err error
if conn == nil && setting.CacheService.Enabled { if conn == nil {
if conn, err = newCache(setting.CacheService.Cache); err != nil { if conn, err = newCache(setting.CacheService.Cache); err != nil {
return err return err
} }

View File

@ -22,9 +22,9 @@ func createTestCache() {
} }
func TestNewContext(t *testing.T) { func TestNewContext(t *testing.T) {
assert.NoError(t, NewContext()) assert.NoError(t, Init())
setting.CacheService.Cache = setting.Cache{Enabled: true, Adapter: "redis", Conn: "some random string"} setting.CacheService.Cache = setting.Cache{Adapter: "redis", Conn: "some random string"}
con, err := newCache(setting.Cache{ con, err := newCache(setting.Cache{
Adapter: "rand", Adapter: "rand",
Conn: "false conf", Conn: "false conf",

View File

@ -8,11 +8,12 @@
package charset package charset
import ( import (
"bufio" "html/template"
"io" "io"
"strings" "strings"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
) )
@ -20,20 +21,18 @@ import (
const RuneNBSP = 0xa0 const RuneNBSP = 0xa0
// EscapeControlHTML escapes the unicode control sequences in a provided html document // EscapeControlHTML escapes the unicode control sequences in a provided html document
func EscapeControlHTML(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) { func EscapeControlHTML(html template.HTML, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output template.HTML) {
sb := &strings.Builder{} sb := &strings.Builder{}
outputStream := &HTMLStreamerWriter{Writer: sb} escaped, _ = EscapeControlReader(strings.NewReader(string(html)), sb, locale, allowed...) // err has been handled in EscapeControlReader
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer) return escaped, template.HTML(sb.String())
if err := StreamHTML(strings.NewReader(text), streamer); err != nil {
streamer.escaped.HasError = true
log.Error("Error whilst escaping: %v", err)
}
return streamer.escaped, sb.String()
} }
// EscapeControlReaders escapes the unicode control sequences in a provided reader of HTML content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte // EscapeControlReader escapes the unicode control sequences in a provided reader of HTML content and writer in a locale and returns the findings as an EscapeStatus
func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) { func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
if !setting.UI.AmbiguousUnicodeDetection {
_, err = io.Copy(writer, reader)
return &EscapeStatus{}, err
}
outputStream := &HTMLStreamerWriter{Writer: writer} outputStream := &HTMLStreamerWriter{Writer: writer}
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer) streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
@ -43,41 +42,3 @@ func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.
} }
return streamer.escaped, err return streamer.escaped, err
} }
// EscapeControlStringReader escapes the unicode control sequences in a provided reader of string content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte. HTML line breaks are not inserted after every newline by this method.
func EscapeControlStringReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
bufRd := bufio.NewReader(reader)
outputStream := &HTMLStreamerWriter{Writer: writer}
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
for {
line, rdErr := bufRd.ReadString('\n')
if len(line) > 0 {
if err := streamer.Text(line); err != nil {
streamer.escaped.HasError = true
log.Error("Error whilst escaping: %v", err)
return streamer.escaped, err
}
}
if rdErr != nil {
if rdErr != io.EOF {
err = rdErr
}
break
}
}
return streamer.escaped, err
}
// EscapeControlString escapes the unicode control sequences in a provided string and returns the findings as an EscapeStatus and the escaped string
func EscapeControlString(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) {
sb := &strings.Builder{}
outputStream := &HTMLStreamerWriter{Writer: sb}
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
if err := streamer.Text(text); err != nil {
streamer.escaped.HasError = true
log.Error("Error whilst escaping: %v", err)
}
return streamer.escaped, sb.String()
}

View File

@ -64,7 +64,7 @@ func (e *escapeStreamer) Text(data string) error {
until, next = nextIdxs[0]+pos, nextIdxs[1]+pos until, next = nextIdxs[0]+pos, nextIdxs[1]+pos
} }
// from pos until until we know that the runes are not \r\t\n or even ' ' // from pos until we know that the runes are not \r\t\n or even ' '
runes := make([]rune, 0, next-until) runes := make([]rune, 0, next-until)
positions := make([]int, 0, next-until+1) positions := make([]int, 0, next-until+1)

View File

@ -4,11 +4,14 @@
package charset package charset
import ( import (
"reflect"
"strings" "strings"
"testing" "testing"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
"github.com/stretchr/testify/assert"
) )
type escapeControlTest struct { type escapeControlTest struct {
@ -132,22 +135,8 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`,
}, },
} }
func TestEscapeControlString(t *testing.T) {
for _, tt := range escapeControlTests {
t.Run(tt.name, func(t *testing.T) {
status, result := EscapeControlString(tt.text, &translation.MockLocale{})
if !reflect.DeepEqual(*status, tt.status) {
t.Errorf("EscapeControlString() status = %v, wanted= %v", status, tt.status)
}
if result != tt.result {
t.Errorf("EscapeControlString()\nresult= %v,\nwanted= %v", result, tt.result)
}
})
}
}
func TestEscapeControlReader(t *testing.T) { func TestEscapeControlReader(t *testing.T) {
// lets add some control characters to the tests // add some control characters to the tests
tests := make([]escapeControlTest, 0, len(escapeControlTests)*3) tests := make([]escapeControlTest, 0, len(escapeControlTests)*3)
copy(tests, escapeControlTests) copy(tests, escapeControlTests)
@ -169,29 +158,20 @@ func TestEscapeControlReader(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
input := strings.NewReader(tt.text)
output := &strings.Builder{} output := &strings.Builder{}
status, err := EscapeControlReader(input, output, &translation.MockLocale{}) status, err := EscapeControlReader(strings.NewReader(tt.text), output, &translation.MockLocale{})
result := output.String() assert.NoError(t, err)
if err != nil { assert.Equal(t, tt.status, *status)
t.Errorf("EscapeControlReader(): err = %v", err) assert.Equal(t, tt.result, output.String())
}
if !reflect.DeepEqual(*status, tt.status) {
t.Errorf("EscapeControlReader() status = %v, wanted= %v", status, tt.status)
}
if result != tt.result {
t.Errorf("EscapeControlReader()\nresult= %v,\nwanted= %v", result, tt.result)
}
}) })
} }
} }
func TestEscapeControlReader_panic(t *testing.T) { func TestSettingAmbiguousUnicodeDetection(t *testing.T) {
bs := make([]byte, 0, 20479) defer test.MockVariableValue(&setting.UI.AmbiguousUnicodeDetection, true)()
bs = append(bs, 'A') _, out := EscapeControlHTML("a test", &translation.MockLocale{})
for i := 0; i < 6826; i++ { assert.EqualValues(t, `a<span class="escaped-code-point" data-escaped="[U+00A0]"><span class="char"> </span></span>test`, out)
bs = append(bs, []byte("—")...) setting.UI.AmbiguousUnicodeDetection = false
} _, out = EscapeControlHTML("a test", &translation.MockLocale{})
_, _ = EscapeControlString(string(bs), &translation.MockLocale{}) assert.EqualValues(t, `a test`, out)
} }

View File

@ -158,6 +158,12 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
Fixer: actions_model.FixRunnersWithoutBelongingOwner, Fixer: actions_model.FixRunnersWithoutBelongingOwner,
FixedMessage: "Removed", FixedMessage: "Removed",
}, },
{
Name: "Topics with empty repository count",
Counter: repo_model.CountOrphanedTopics,
Fixer: repo_model.DeleteOrphanedTopics,
FixedMessage: "Removed",
},
} }
// TODO: function to recalc all counters // TODO: function to recalc all counters

View File

@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/storage"
repo_service "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository"
"xorm.io/builder" "xorm.io/builder"
@ -31,6 +32,10 @@ func countOrphanedRepos(ctx context.Context) (int64, error) {
// deleteOrphanedRepos delete repository where user of owner_id do not exist // deleteOrphanedRepos delete repository where user of owner_id do not exist
func deleteOrphanedRepos(ctx context.Context) (int64, error) { func deleteOrphanedRepos(ctx context.Context) (int64, error) {
if err := storage.Init(); err != nil {
return 0, err
}
batchSize := db.MaxBatchInsertSize("repository") batchSize := db.MaxBatchInsertSize("repository")
e := db.GetEngine(ctx) e := db.GetEngine(ctx)
var deleted int64 var deleted int64

View File

@ -39,7 +39,7 @@ func TestReadingBlameOutput(t *testing.T) {
} }
for _, bypass := range []bool{false, true} { for _, bypass := range []bool{false, true} {
blameReader, err := CreateBlameReader(ctx, &Sha1ObjectFormat{}, "./tests/repos/repo5_pulls", commit, "README.md", bypass) blameReader, err := CreateBlameReader(ctx, Sha1ObjectFormat, "./tests/repos/repo5_pulls", commit, "README.md", bypass)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, blameReader) assert.NotNil(t, blameReader)
defer blameReader.Close() defer blameReader.Close()

View File

@ -14,7 +14,6 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"time" "time"
"unsafe"
"code.gitea.io/gitea/modules/git/internal" //nolint:depguard // only this file can use the internal type CmdArg, other files and packages should use AddXxx functions "code.gitea.io/gitea/modules/git/internal" //nolint:depguard // only this file can use the internal type CmdArg, other files and packages should use AddXxx functions
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -389,15 +388,11 @@ func (r *runStdError) IsExitCode(code int) bool {
return false return false
} }
func bytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b)) // that's what Golang's strings.Builder.String() does (go/src/strings/builder.go)
}
// RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr). // RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) { func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
stdoutBytes, stderrBytes, err := c.RunStdBytes(opts) stdoutBytes, stderrBytes, err := c.RunStdBytes(opts)
stdout = bytesToString(stdoutBytes) stdout = util.UnsafeBytesToString(stdoutBytes)
stderr = bytesToString(stderrBytes) stderr = util.UnsafeBytesToString(stderrBytes)
if err != nil { if err != nil {
return stdout, stderr, &runStdError{err: err, stderr: stderr} return stdout, stderr, &runStdError{err: err, stderr: stderr}
} }
@ -432,7 +427,7 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS
err := c.Run(newOpts) err := c.Run(newOpts)
stderr = stderrBuf.Bytes() stderr = stderrBuf.Bytes()
if err != nil { if err != nil {
return nil, stderr, &runStdError{err: err, stderr: bytesToString(stderr)} return nil, stderr, &runStdError{err: err, stderr: util.UnsafeBytesToString(stderr)}
} }
// even if there is no err, there could still be some stderr output // even if there is no err, there could still be some stderr output
return stdoutBuf.Bytes(), stderr, nil return stdoutBuf.Bytes(), stderr, nil

View File

@ -236,7 +236,7 @@ func (c *Commit) IsForcePush(oldCommitID string) (bool, error) {
if err != nil { if err != nil {
return false, err return false, err
} }
if oldCommitID == objectFormat.Empty().String() { if oldCommitID == objectFormat.EmptyObjectID().String() {
return false, nil return false, nil
} }

View File

@ -153,7 +153,7 @@ func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string,
if typ != "commit" { if typ != "commit" {
return nil, fmt.Errorf("unexpected type: %s for commit id: %s", typ, commitID) return nil, fmt.Errorf("unexpected type: %s for commit id: %s", typ, commitID)
} }
c, err = CommitFromReader(commit.repo, commit.ID.Type().MustIDFromString(commitID), io.LimitReader(batchReader, size)) c, err = CommitFromReader(commit.repo, MustIDFromString(commitID), io.LimitReader(batchReader, size))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -71,10 +71,10 @@ readLoop:
switch string(split[0]) { switch string(split[0]) {
case "tree": case "tree":
commit.Tree = *NewTree(gitRepo, objectID.Type().MustIDFromString(string(data))) commit.Tree = *NewTree(gitRepo, MustIDFromString(string(data)))
_, _ = payloadSB.Write(line) _, _ = payloadSB.Write(line)
case "parent": case "parent":
commit.Parents = append(commit.Parents, objectID.Type().MustIDFromString(string(data))) commit.Parents = append(commit.Parents, MustIDFromString(string(data)))
_, _ = payloadSB.Write(line) _, _ = payloadSB.Write(line)
case "author": case "author":
commit.Author = &Signature{} commit.Author = &Signature{}

View File

@ -135,8 +135,8 @@ func TestHasPreviousCommit(t *testing.T) {
commit, err := repo.GetCommit("8006ff9adbf0cb94da7dad9e537e53817f9fa5c0") commit, err := repo.GetCommit("8006ff9adbf0cb94da7dad9e537e53817f9fa5c0")
assert.NoError(t, err) assert.NoError(t, err)
parentSHA := repo.objectFormat.MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2") parentSHA := MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2")
notParentSHA := repo.objectFormat.MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3") notParentSHA := MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3")
haz, err := commit.HasPreviousCommit(parentSHA) haz, err := commit.HasPreviousCommit(parentSHA)
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -39,7 +39,7 @@ func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache
if cache == nil { if cache == nil {
return nil return nil
} }
if !setting.CacheService.LastCommit.Enabled || count < setting.CacheService.LastCommit.CommitsCount { if count < setting.CacheService.LastCommit.CommitsCount {
return nil return nil
} }
@ -92,11 +92,7 @@ func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) {
// GetCommitByPath gets the last commit for the entry in the provided commit // GetCommitByPath gets the last commit for the entry in the provided commit
func (c *LastCommitCache) GetCommitByPath(commitID, entryPath string) (*Commit, error) { func (c *LastCommitCache) GetCommitByPath(commitID, entryPath string) (*Commit, error) {
objectFormat, err := c.repo.GetObjectFormat() sha, err := NewIDFromString(commitID)
if err != nil {
return nil, err
}
sha, err := objectFormat.NewIDFromString(commitID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -5,97 +5,89 @@ package git
import ( import (
"crypto/sha1" "crypto/sha1"
"fmt"
"regexp" "regexp"
"strings" "strconv"
)
type ObjectFormatID int
const (
Sha1 ObjectFormatID = iota
) )
// sha1Pattern can be used to determine if a string is an valid sha // sha1Pattern can be used to determine if a string is an valid sha
var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`) var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
type ObjectFormat interface { type ObjectFormat interface {
ID() ObjectFormatID // Name returns the name of the object format
String() string Name() string
// EmptyObjectID creates a new empty ObjectID from an object format hash name
// Empty is the hash of empty git EmptyObjectID() ObjectID
Empty() ObjectID
// EmptyTree is the hash of an empty tree // EmptyTree is the hash of an empty tree
EmptyTree() ObjectID EmptyTree() ObjectID
// FullLength is the length of the hash's hex string // FullLength is the length of the hash's hex string
FullLength() int FullLength() int
// IsValid returns true if the input is a valid hash
IsValid(input string) bool IsValid(input string) bool
// MustID creates a new ObjectID from a byte slice
MustID(b []byte) ObjectID MustID(b []byte) ObjectID
MustIDFromString(s string) ObjectID // ComputeHash compute the hash for a given ObjectType and content
NewID(b []byte) (ObjectID, error) ComputeHash(t ObjectType, content []byte) ObjectID
NewIDFromString(s string) (ObjectID, error)
NewEmptyID() ObjectID
NewHasher() HasherInterface
} }
type Sha1ObjectFormat struct{} type Sha1ObjectFormatImpl struct{}
func (*Sha1ObjectFormat) ID() ObjectFormatID { return Sha1 } var (
func (*Sha1ObjectFormat) String() string { return "sha1" } emptyObjectID = &Sha1Hash{}
func (*Sha1ObjectFormat) Empty() ObjectID { return &Sha1Hash{} } emptyTree = &Sha1Hash{
func (*Sha1ObjectFormat) EmptyTree() ObjectID {
return &Sha1Hash{
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04, 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
} }
)
func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
return emptyObjectID
} }
func (*Sha1ObjectFormat) FullLength() int { return 40 }
func (*Sha1ObjectFormat) IsValid(input string) bool { func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
return emptyTree
}
func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
func (Sha1ObjectFormatImpl) IsValid(input string) bool {
return sha1Pattern.MatchString(input) return sha1Pattern.MatchString(input)
} }
func (*Sha1ObjectFormat) MustID(b []byte) ObjectID { func (Sha1ObjectFormatImpl) MustID(b []byte) ObjectID {
var id Sha1Hash var id Sha1Hash
copy(id[0:20], b) copy(id[0:20], b)
return &id return &id
} }
func (h *Sha1ObjectFormat) MustIDFromString(s string) ObjectID { // ComputeHash compute the hash for a given ObjectType and content
return MustIDFromString(h, s) func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID {
hasher := sha1.New()
_, _ = hasher.Write(t.Bytes())
_, _ = hasher.Write([]byte(" "))
_, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
_, _ = hasher.Write([]byte{0})
// HashSum generates a SHA1 for the provided hash
var sha1 Sha1Hash
copy(sha1[:], hasher.Sum(nil))
return &sha1
} }
func (h *Sha1ObjectFormat) NewID(b []byte) (ObjectID, error) { var Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
return IDFromRaw(h, b)
var SupportedObjectFormats = []ObjectFormat{
Sha1ObjectFormat,
// TODO: add sha256
} }
func (h *Sha1ObjectFormat) NewIDFromString(s string) (ObjectID, error) { func ObjectFormatFromName(name string) ObjectFormat {
return genericIDFromString(h, s) for _, objectFormat := range SupportedObjectFormats {
if name == objectFormat.Name() {
return objectFormat
} }
func (*Sha1ObjectFormat) NewEmptyID() ObjectID {
return NewSha1()
} }
func (h *Sha1ObjectFormat) NewHasher() HasherInterface {
return &Sha1Hasher{sha1.New()}
}
func ObjectFormatFromID(id ObjectFormatID) ObjectFormat {
switch id {
case Sha1:
return &Sha1ObjectFormat{}
}
return nil return nil
} }
func ObjectFormatFromString(hash string) (ObjectFormat, error) { func IsValidObjectFormat(name string) bool {
switch strings.ToLower(hash) { return ObjectFormatFromName(name) != nil
case "sha1":
return &Sha1ObjectFormat{}, nil
}
return nil, fmt.Errorf("unknown hash type: %s", hash)
} }

View File

@ -6,11 +6,7 @@ package git
import ( import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"hash"
"strconv"
"strings"
) )
type ObjectID interface { type ObjectID interface {
@ -31,59 +27,40 @@ func (h *Sha1Hash) IsZero() bool {
return bytes.Equal(empty[:], h[:]) return bytes.Equal(empty[:], h[:])
} }
func (h *Sha1Hash) RawValue() []byte { return h[:] } func (h *Sha1Hash) RawValue() []byte { return h[:] }
func (*Sha1Hash) Type() ObjectFormat { return &Sha1ObjectFormat{} } func (*Sha1Hash) Type() ObjectFormat { return Sha1ObjectFormat }
func NewSha1() *Sha1Hash { var _ ObjectID = &Sha1Hash{}
return &Sha1Hash{}
}
// NewHash is for generic implementations func MustIDFromString(hexHash string) ObjectID {
func NewHash(hash string) (ObjectID, error) { id, err := NewIDFromString(hexHash)
hash = strings.ToLower(hash)
switch hash {
case "sha1":
return &Sha1Hash{}, nil
}
return nil, errors.New("unsupported hash type")
}
func IDFromRaw(h ObjectFormat, b []byte) (ObjectID, error) {
if len(b) != h.FullLength()/2 {
return h.Empty(), fmt.Errorf("length must be %d: %v", h.FullLength(), b)
}
return h.MustID(b), nil
}
func MustIDFromString(h ObjectFormat, s string) ObjectID {
b, _ := hex.DecodeString(s)
return h.MustID(b)
}
func genericIDFromString(h ObjectFormat, s string) (ObjectID, error) {
s = strings.TrimSpace(s)
if len(s) != h.FullLength() {
return h.Empty(), fmt.Errorf("length must be %d: %s", h.FullLength(), s)
}
b, err := hex.DecodeString(s)
if err != nil { if err != nil {
return h.Empty(), err panic(err)
} }
return h.NewID(b) return id
} }
func IDFromString(hexHash string) (ObjectID, error) { func NewIDFromString(hexHash string) (ObjectID, error) {
switch len(hexHash) { var theObjectFormat ObjectFormat
case 40: for _, objectFormat := range SupportedObjectFormats {
hashType := Sha1ObjectFormat{} if len(hexHash) == objectFormat.FullLength() {
h, err := hashType.NewIDFromString(hexHash) theObjectFormat = objectFormat
break
}
}
if theObjectFormat == nil {
return nil, fmt.Errorf("length %d has no matched object format: %s", len(hexHash), hexHash)
}
b, err := hex.DecodeString(hexHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return h, nil
}
return nil, fmt.Errorf("invalid hash hex string: '%s' len: %d", hexHash, len(hexHash)) if len(b) != theObjectFormat.FullLength()/2 {
return theObjectFormat.EmptyObjectID(), fmt.Errorf("length must be %d: %v", theObjectFormat.FullLength(), b)
}
return theObjectFormat.MustID(b), nil
} }
func IsEmptyCommitID(commitID string) bool { func IsEmptyCommitID(commitID string) bool {
@ -91,7 +68,7 @@ func IsEmptyCommitID(commitID string) bool {
return true return true
} }
id, err := IDFromString(commitID) id, err := NewIDFromString(commitID)
if err != nil { if err != nil {
return false return false
} }
@ -99,37 +76,9 @@ func IsEmptyCommitID(commitID string) bool {
return id.IsZero() return id.IsZero()
} }
// HasherInterface is a struct that will generate a Hash
type HasherInterface interface {
hash.Hash
HashSum() ObjectID
}
type Sha1Hasher struct {
hash.Hash
}
// ComputeBlobHash compute the hash for a given blob content // ComputeBlobHash compute the hash for a given blob content
func ComputeBlobHash(hashType ObjectFormat, content []byte) ObjectID { func ComputeBlobHash(hashType ObjectFormat, content []byte) ObjectID {
return ComputeHash(hashType, ObjectBlob, content) return hashType.ComputeHash(ObjectBlob, content)
}
// ComputeHash compute the hash for a given ObjectType and content
func ComputeHash(hashType ObjectFormat, t ObjectType, content []byte) ObjectID {
h := hashType.NewHasher()
_, _ = h.Write(t.Bytes())
_, _ = h.Write([]byte(" "))
_, _ = h.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
_, _ = h.Write([]byte{0})
return h.HashSum()
}
// HashSum generates a SHA1 for the provided hash
func (h *Sha1Hasher) HashSum() ObjectID {
var sha1 Sha1Hash
copy(sha1[:], h.Hash.Sum(nil))
return &sha1
} }
type ErrInvalidSHA struct { type ErrInvalidSHA struct {

View File

@ -12,7 +12,7 @@ import (
func ParseGogitHash(h plumbing.Hash) ObjectID { func ParseGogitHash(h plumbing.Hash) ObjectID {
switch hash.Size { switch hash.Size {
case 20: case 20:
return ObjectFormatFromID(Sha1).MustID(h[:]) return Sha1ObjectFormat.MustID(h[:])
} }
return nil return nil

View File

@ -10,7 +10,7 @@ import (
) )
func TestIsValidSHAPattern(t *testing.T) { func TestIsValidSHAPattern(t *testing.T) {
h := NewSha1().Type() h := Sha1ObjectFormat
assert.True(t, h.IsValid("fee1")) assert.True(t, h.IsValid("fee1"))
assert.True(t, h.IsValid("abc000")) assert.True(t, h.IsValid("abc000"))
assert.True(t, h.IsValid("9023902390239023902390239023902390239023")) assert.True(t, h.IsValid("9023902390239023902390239023902390239023"))

View File

@ -57,7 +57,7 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data)) return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data))
} }
var err error var err error
entry.ID, err = IDFromString(string(data[pos : pos+hash.Size*2])) entry.ID, err = NewIDFromString(string(data[pos : pos+hash.Size*2]))
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid ls-tree output: %w", err) return nil, fmt.Errorf("invalid ls-tree output: %w", err)
} }

View File

@ -28,9 +28,9 @@ func TestParseTreeEntries(t *testing.T) {
Input: "100644 blob 61ab7345a1a3bbc590068ccae37b8515cfc5843c 1022\texample/file2.txt\n", Input: "100644 blob 61ab7345a1a3bbc590068ccae37b8515cfc5843c 1022\texample/file2.txt\n",
Expected: []*TreeEntry{ Expected: []*TreeEntry{
{ {
ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), ID: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
gogitTreeEntry: &object.TreeEntry{ gogitTreeEntry: &object.TreeEntry{
Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), Hash: plumbing.Hash(MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
Name: "example/file2.txt", Name: "example/file2.txt",
Mode: filemode.Regular, Mode: filemode.Regular,
}, },
@ -44,9 +44,9 @@ func TestParseTreeEntries(t *testing.T) {
"040000 tree 1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8 -\texample\n", "040000 tree 1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8 -\texample\n",
Expected: []*TreeEntry{ Expected: []*TreeEntry{
{ {
ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), ID: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
gogitTreeEntry: &object.TreeEntry{ gogitTreeEntry: &object.TreeEntry{
Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), Hash: plumbing.Hash(MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
Name: "example/\n.txt", Name: "example/\n.txt",
Mode: filemode.Symlink, Mode: filemode.Symlink,
}, },
@ -54,10 +54,10 @@ func TestParseTreeEntries(t *testing.T) {
sized: true, sized: true,
}, },
{ {
ID: ObjectFormatFromID(Sha1).MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"), ID: MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"),
sized: true, sized: true,
gogitTreeEntry: &object.TreeEntry{ gogitTreeEntry: &object.TreeEntry{
Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8").RawValue()), Hash: plumbing.Hash(MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8").RawValue()),
Name: "example", Name: "example",
Mode: filemode.Dir, Mode: filemode.Dir,
}, },
@ -67,7 +67,7 @@ func TestParseTreeEntries(t *testing.T) {
} }
for _, testCase := range testCases { for _, testCase := range testCases {
entries, err := ParseTreeEntries(ObjectFormatFromID(Sha1), []byte(testCase.Input)) entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte(testCase.Input))
assert.NoError(t, err) assert.NoError(t, err)
if len(entries) > 1 { if len(entries) > 1 {
fmt.Println(testCase.Expected[0].ID) fmt.Println(testCase.Expected[0].ID)

View File

@ -72,7 +72,7 @@ func parseTreeEntries(objectFormat ObjectFormat, data []byte, ptree *Tree) ([]*T
return nil, fmt.Errorf("unknown type: %v", string(entryMode)) return nil, fmt.Errorf("unknown type: %v", string(entryMode))
} }
entry.ID, err = objectFormat.NewIDFromString(string(entryObjectID)) entry.ID, err = NewIDFromString(string(entryObjectID))
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err) return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err)
} }

View File

@ -12,7 +12,7 @@ import (
) )
func TestParseTreeEntriesLong(t *testing.T) { func TestParseTreeEntriesLong(t *testing.T) {
objectFormat := ObjectFormatFromID(Sha1) objectFormat := Sha1ObjectFormat
testCases := []struct { testCases := []struct {
Input string Input string
@ -26,28 +26,28 @@ func TestParseTreeEntriesLong(t *testing.T) {
`, `,
Expected: []*TreeEntry{ Expected: []*TreeEntry{
{ {
ID: objectFormat.MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"), ID: MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
name: "README.md", name: "README.md",
entryMode: EntryModeBlob, entryMode: EntryModeBlob,
size: 8218, size: 8218,
sized: true, sized: true,
}, },
{ {
ID: objectFormat.MustIDFromString("037f27dc9d353ae4fd50f0474b2194c593914e35"), ID: MustIDFromString("037f27dc9d353ae4fd50f0474b2194c593914e35"),
name: "README_ZH.md", name: "README_ZH.md",
entryMode: EntryModeBlob, entryMode: EntryModeBlob,
size: 4681, size: 4681,
sized: true, sized: true,
}, },
{ {
ID: objectFormat.MustIDFromString("9846a94f7e8350a916632929d0fda38c90dd2ca8"), ID: MustIDFromString("9846a94f7e8350a916632929d0fda38c90dd2ca8"),
name: "SECURITY.md", name: "SECURITY.md",
entryMode: EntryModeBlob, entryMode: EntryModeBlob,
size: 429, size: 429,
sized: true, sized: true,
}, },
{ {
ID: objectFormat.MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"), ID: MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
name: "assets", name: "assets",
entryMode: EntryModeTree, entryMode: EntryModeTree,
sized: true, sized: true,
@ -66,7 +66,7 @@ func TestParseTreeEntriesLong(t *testing.T) {
} }
func TestParseTreeEntriesShort(t *testing.T) { func TestParseTreeEntriesShort(t *testing.T) {
objectFormat := ObjectFormatFromID(Sha1) objectFormat := Sha1ObjectFormat
testCases := []struct { testCases := []struct {
Input string Input string
@ -78,12 +78,12 @@ func TestParseTreeEntriesShort(t *testing.T) {
`, `,
Expected: []*TreeEntry{ Expected: []*TreeEntry{
{ {
ID: objectFormat.MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"), ID: MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
name: "README.md", name: "README.md",
entryMode: EntryModeBlob, entryMode: EntryModeBlob,
}, },
{ {
ID: objectFormat.MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"), ID: MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
name: "assets", name: "assets",
entryMode: EntryModeTree, entryMode: EntryModeTree,
}, },
@ -102,7 +102,7 @@ func TestParseTreeEntriesShort(t *testing.T) {
func TestParseTreeEntriesInvalid(t *testing.T) { func TestParseTreeEntriesInvalid(t *testing.T) {
// there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315 // there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315
entries, err := ParseTreeEntries(ObjectFormatFromID(Sha1), []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af")) entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af"))
assert.Error(t, err) assert.Error(t, err)
assert.Len(t, entries, 0) assert.Len(t, entries, 0)
} }

View File

@ -115,11 +115,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
continue continue
case "commit": case "commit":
// Read in the commit to get its tree and in case this is one of the last used commits // Read in the commit to get its tree and in case this is one of the last used commits
objectFormat, err := repo.GetObjectFormat() curCommit, err = git.CommitFromReader(repo, git.MustIDFromString(string(commitID)), io.LimitReader(batchReader, size))
if err != nil {
return nil, err
}
curCommit, err = git.CommitFromReader(repo, objectFormat.MustIDFromString(string(commitID)), io.LimitReader(batchReader, size))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -205,7 +205,7 @@ func RefURL(repoURL, ref string) string {
return repoURL + "/src/branch/" + refName return repoURL + "/src/branch/" + refName
case refFullName.IsTag(): case refFullName.IsTag():
return repoURL + "/src/tag/" + refName return repoURL + "/src/tag/" + refName
case !ObjectFormatFromID(Sha1).IsValid(ref): case !Sha1ObjectFormat.IsValid(ref):
// assume they mean a branch // assume they mean a branch
return repoURL + "/src/branch/" + refName return repoURL + "/src/branch/" + refName
default: default:

View File

@ -81,7 +81,7 @@ func GetObjectFormatOfRepo(ctx context.Context, repoPath string) (ObjectFormat,
return nil, errors.New(stderr.String()) return nil, errors.New(stderr.String())
} }
h, err := IDFromString(strings.TrimRight(stdout.String(), "\n")) h, err := NewIDFromString(strings.TrimRight(stdout.String(), "\n"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -90,7 +90,7 @@ func GetObjectFormatOfRepo(ctx context.Context, repoPath string) (ObjectFormat,
} }
// InitRepository initializes a new Git repository. // InitRepository initializes a new Git repository.
func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormat ObjectFormat) error { func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormatName string) error {
err := os.MkdirAll(repoPath, os.ModePerm) err := os.MkdirAll(repoPath, os.ModePerm)
if err != nil { if err != nil {
return err return err
@ -98,7 +98,13 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
cmd := NewCommand(ctx, "init") cmd := NewCommand(ctx, "init")
if SupportHashSha256 { if SupportHashSha256 {
cmd.AddOptionValues("--object-format", objectFormat.String()) if objectFormatName == "" {
objectFormatName = Sha1ObjectFormat.Name()
}
if !IsValidObjectFormat(objectFormatName) {
return fmt.Errorf("invalid object format: %s", objectFormatName)
}
cmd.AddOptionValues("--object-format", objectFormatName)
} }
if bare { if bare {
cmd.AddArguments("--bare") cmd.AddArguments("--bare")

View File

@ -5,7 +5,7 @@ package git
// GetBlob finds the blob object in the repository. // GetBlob finds the blob object in the repository.
func (repo *Repository) GetBlob(idStr string) (*Blob, error) { func (repo *Repository) GetBlob(idStr string) (*Blob, error) {
id, err := repo.objectFormat.NewIDFromString(idStr) id, err := NewIDFromString(idStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -61,7 +61,7 @@ func TestRepository_GetBlob_NoId(t *testing.T) {
defer r.Close() defer r.Close()
testCase := "" testCase := ""
testError := fmt.Errorf("length must be 40: %s", testCase) testError := fmt.Errorf("length %d has no matched object format: %s", len(testCase), testCase)
blob, err := r.GetBlob(testCase) blob, err := r.GetBlob(testCase)
assert.Nil(t, blob) assert.Nil(t, blob)

View File

@ -63,7 +63,7 @@ func (repo *Repository) getCommitByPathWithID(id ObjectID, relpath string) (*Com
return nil, runErr return nil, runErr
} }
id, err := repo.objectFormat.NewIDFromString(stdout) id, err := NewIDFromString(stdout)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -254,7 +254,7 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
} }
return commits, err return commits, err
} }
objectID, err := repo.objectFormat.NewIDFromString(string(shaline[0:len])) objectID, err := NewIDFromString(string(shaline[0:len]))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -43,7 +43,7 @@ func (repo *Repository) RemoveReference(name string) error {
func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) { func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
objectFormat := repo.objectFormat objectFormat := repo.objectFormat
if len(commitID) == hash.HexSize && objectFormat.IsValid(commitID) { if len(commitID) == hash.HexSize && objectFormat.IsValid(commitID) {
ID, err := objectFormat.NewIDFromString(commitID) ID, err := NewIDFromString(commitID)
if err == nil { if err == nil {
return ID, nil return ID, nil
} }
@ -54,12 +54,12 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
if err != nil { if err != nil {
if strings.Contains(err.Error(), "unknown revision or path") || if strings.Contains(err.Error(), "unknown revision or path") ||
strings.Contains(err.Error(), "fatal: Needed a single revision") { strings.Contains(err.Error(), "fatal: Needed a single revision") {
return objectFormat.Empty(), ErrNotExist{commitID, ""} return objectFormat.EmptyObjectID(), ErrNotExist{commitID, ""}
} }
return objectFormat.Empty(), err return objectFormat.EmptyObjectID(), err
} }
return objectFormat.NewIDFromString(actualCommitID) return NewIDFromString(actualCommitID)
} }
// IsCommitExist returns true if given commit exists in current repository. // IsCommitExist returns true if given commit exists in current repository.

View File

@ -135,7 +135,7 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id ObjectID)
func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) { func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
IDType := repo.objectFormat IDType := repo.objectFormat
if len(commitID) == IDType.FullLength() && IDType.IsValid(commitID) { if len(commitID) == IDType.FullLength() && IDType.IsValid(commitID) {
ID, err := repo.objectFormat.NewIDFromString(commitID) ID, err := NewIDFromString(commitID)
if err == nil { if err == nil {
return ID, nil return ID, nil
} }
@ -155,5 +155,5 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
return nil, err return nil, err
} }
return repo.objectFormat.MustIDFromString(string(sha)), nil return MustIDFromString(string(sha)), nil
} }

View File

@ -22,7 +22,7 @@ func (r *Repository) CommitNodeIndex() (cgobject.CommitNodeIndex, *os.File) {
file, err := os.Open(indexPath) file, err := os.Open(indexPath)
if err == nil { if err == nil {
var index commitgraph.Index var index commitgraph.Index // TODO: in newer go-git, it might need to use "github.com/go-git/go-git/v5/plumbing/format/commitgraph/v2" package to compile
index, err = commitgraph.OpenFileIndex(file) index, err = commitgraph.OpenFileIndex(file)
if err == nil { if err == nil {
return cgobject.NewGraphCommitNodeIndex(index, r.gogitRepo.Storer), file return cgobject.NewGraphCommitNodeIndex(index, r.gogitRepo.Storer), file

View File

@ -284,7 +284,7 @@ func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
// If base is the SHA of an empty tree (EmptyTreeSHA), it returns the files changes from the initial commit to the head commit // If base is the SHA of an empty tree (EmptyTreeSHA), it returns the files changes from the initial commit to the head commit
func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, error) { func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, error) {
cmd := NewCommand(repo.Ctx, "diff-tree", "--name-only", "--root", "--no-commit-id", "-r", "-z") cmd := NewCommand(repo.Ctx, "diff-tree", "--name-only", "--root", "--no-commit-id", "-r", "-z")
if base == repo.objectFormat.Empty().String() { if base == repo.objectFormat.EmptyObjectID().String() {
cmd.AddDynamicArguments(head) cmd.AddDynamicArguments(head)
} else { } else {
cmd.AddDynamicArguments(base, head) cmd.AddDynamicArguments(base, head)

View File

@ -131,12 +131,12 @@ func TestGetCommitFilesChanged(t *testing.T) {
files []string files []string
}{ }{
{ {
repo.objectFormat.Empty().String(), repo.objectFormat.EmptyObjectID().String(),
"95bb4d39648ee7e325106df01a621c530863a653", "95bb4d39648ee7e325106df01a621c530863a653",
[]string{"file1.txt"}, []string{"file1.txt"},
}, },
{ {
repo.objectFormat.Empty().String(), repo.objectFormat.EmptyObjectID().String(),
"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
[]string{"file2.txt"}, []string{"file2.txt"},
}, },

View File

@ -30,7 +30,7 @@ func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string)
treeish = res[:len(res)-1] treeish = res[:len(res)-1]
} }
} }
id, err := objectFormat.NewIDFromString(treeish) id, err := NewIDFromString(treeish)
if err != nil { if err != nil {
return err return err
} }
@ -101,7 +101,7 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
for _, file := range filenames { for _, file := range filenames {
if file != "" { if file != "" {
buffer.WriteString("0 ") buffer.WriteString("0 ")
buffer.WriteString(repo.objectFormat.Empty().String()) buffer.WriteString(repo.objectFormat.EmptyObjectID().String())
buffer.WriteByte('\t') buffer.WriteByte('\t')
buffer.WriteString(file) buffer.WriteString(file)
buffer.WriteByte('\000') buffer.WriteByte('\000')
@ -128,7 +128,7 @@ func (repo *Repository) WriteTree() (*Tree, error) {
if runErr != nil { if runErr != nil {
return nil, runErr return nil, runErr
} }
id, err := repo.objectFormat.NewIDFromString(strings.TrimSpace(stdout)) id, err := NewIDFromString(strings.TrimSpace(stdout))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -39,7 +39,7 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
return nil, ErrNotExist{commitID, ""} return nil, ErrNotExist{commitID, ""}
} }
sha, err := repo.objectFormat.NewIDFromString(string(shaBytes)) sha, err := NewIDFromString(string(shaBytes))
if err != nil { if err != nil {
log.Debug("Unable to get commit for: %s. Err: %v", commitID, err) log.Debug("Unable to get commit for: %s. Err: %v", commitID, err)
return nil, ErrNotExist{commitID, ""} return nil, ErrNotExist{commitID, ""}

View File

@ -46,7 +46,7 @@ func (repo *Repository) GetObjectFormat() (ObjectFormat, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
hash, err := IDFromString(str) hash, err := NewIDFromString(str)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -62,7 +62,7 @@ func (repo *Repository) HashObject(reader io.Reader) (ObjectID, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return repo.objectFormat.NewIDFromString(idStr) return NewIDFromString(idStr)
} }
func (repo *Repository) hashObject(reader io.Reader, save bool) (string, error) { func (repo *Repository) hashObject(reader io.Reader, save bool) (string, error) {

View File

@ -75,7 +75,7 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
if pattern == "" || strings.HasPrefix(refName, pattern) { if pattern == "" || strings.HasPrefix(refName, pattern) {
r := &Reference{ r := &Reference{
Name: refName, Name: refName,
Object: repo.objectFormat.MustIDFromString(sha), Object: MustIDFromString(sha),
Type: typ, Type: typ,
repo: repo, repo: repo,
} }

View File

@ -84,7 +84,7 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
return nil, err return nil, err
} }
id, err := repo.objectFormat.NewIDFromString(idStr) id, err := NewIDFromString(idStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -98,7 +98,7 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
// GetTagWithID returns a Git tag by given name and ID // GetTagWithID returns a Git tag by given name and ID
func (repo *Repository) GetTagWithID(idStr, name string) (*Tag, error) { func (repo *Repository) GetTagWithID(idStr, name string) (*Tag, error) {
id, err := repo.objectFormat.NewIDFromString(idStr) id, err := NewIDFromString(idStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -165,7 +165,7 @@ func parseTagRef(objectFormat ObjectFormat, ref map[string]string) (tag *Tag, er
Name: ref["refname:short"], Name: ref["refname:short"],
} }
tag.ID, err = objectFormat.NewIDFromString(ref["objectname"]) tag.ID, err = NewIDFromString(ref["objectname"])
if err != nil { if err != nil {
return nil, fmt.Errorf("parse objectname '%s': %w", ref["objectname"], err) return nil, fmt.Errorf("parse objectname '%s': %w", ref["objectname"], err)
} }
@ -175,7 +175,7 @@ func parseTagRef(objectFormat ObjectFormat, ref map[string]string) (tag *Tag, er
tag.Object = tag.ID tag.Object = tag.ID
} else { } else {
// annotated tag // annotated tag
tag.Object, err = objectFormat.NewIDFromString(ref["object"]) tag.Object, err = NewIDFromString(ref["object"])
if err != nil { if err != nil {
return nil, fmt.Errorf("parse object '%s': %w", ref["object"], err) return nil, fmt.Errorf("parse object '%s': %w", ref["object"], err)
} }
@ -208,7 +208,7 @@ func parseTagRef(objectFormat ObjectFormat, ref map[string]string) (tag *Tag, er
// GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag // GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag
func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) { func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) {
id, err := repo.objectFormat.NewIDFromString(sha) id, err := NewIDFromString(sha)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -88,7 +88,7 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) {
// every tag should have a commit ID so return all errors // every tag should have a commit ID so return all errors
return nil, err return nil, err
} }
commitID, err := IDFromString(commitIDStr) commitID, err := NewIDFromString(commitIDStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -64,7 +64,7 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) {
// every tag should have a commit ID so return all errors // every tag should have a commit ID so return all errors
return nil, err return nil, err
} }
commitID, err := repo.objectFormat.NewIDFromString(commitIDStr) commitID, err := NewIDFromString(commitIDStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -194,7 +194,7 @@ func TestRepository_GetAnnotatedTag(t *testing.T) {
} }
func TestRepository_parseTagRef(t *testing.T) { func TestRepository_parseTagRef(t *testing.T) {
sha1 := ObjectFormatFromID(Sha1) sha1 := Sha1ObjectFormat
tests := []struct { tests := []struct {
name string name string
@ -224,8 +224,8 @@ func TestRepository_parseTagRef(t *testing.T) {
want: &Tag{ want: &Tag{
Name: "v1.9.1", Name: "v1.9.1",
ID: sha1.MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"), ID: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
Object: sha1.MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"), Object: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
Type: "commit", Type: "commit",
Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"), Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"),
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n", Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n",
@ -253,8 +253,8 @@ func TestRepository_parseTagRef(t *testing.T) {
want: &Tag{ want: &Tag{
Name: "v0.0.1", Name: "v0.0.1",
ID: sha1.MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"), ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
Object: sha1.MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"), Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
Type: "tag", Type: "tag",
Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"), Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"),
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n", Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n",
@ -311,8 +311,8 @@ qbHDASXl
want: &Tag{ want: &Tag{
Name: "v0.0.1", Name: "v0.0.1",
ID: sha1.MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"), ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
Object: sha1.MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"), Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
Type: "tag", Type: "tag",
Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"), Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"),
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md", Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md",

View File

@ -63,5 +63,5 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt
if err != nil { if err != nil {
return nil, ConcatenateError(err, stderr.String()) return nil, ConcatenateError(err, stderr.String())
} }
return repo.objectFormat.NewIDFromString(strings.TrimSpace(stdout.String())) return NewIDFromString(strings.TrimSpace(stdout.String()))
} }

View File

@ -30,7 +30,7 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
idStr = res[:len(res)-1] idStr = res[:len(res)-1]
} }
} }
id, err := repo.objectFormat.NewIDFromString(idStr) id, err := NewIDFromString(idStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -75,7 +75,7 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
idStr = res idStr = res
} }
} }
id, err := repo.objectFormat.NewIDFromString(idStr) id, err := NewIDFromString(idStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -35,8 +35,8 @@ func (tag *Tag) Commit(gitRepo *Repository) (*Commit, error) {
// \n\n separate headers from message // \n\n separate headers from message
func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) { func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) {
tag := new(Tag) tag := new(Tag)
tag.ID = objectFormat.NewEmptyID() tag.ID = objectFormat.EmptyObjectID()
tag.Object = objectFormat.NewEmptyID() tag.Object = objectFormat.EmptyObjectID()
tag.Tagger = &Signature{} tag.Tagger = &Signature{}
// we now have the contents of the commit object. Let's investigate... // we now have the contents of the commit object. Let's investigate...
nextline := 0 nextline := 0
@ -50,7 +50,7 @@ l:
reftype := line[:spacepos] reftype := line[:spacepos]
switch string(reftype) { switch string(reftype) {
case "object": case "object":
id, err := objectFormat.NewIDFromString(string(line[spacepos+1:])) id, err := NewIDFromString(string(line[spacepos+1:]))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -22,7 +22,7 @@ tagger Lucas Michot <lucas@semalead.com> 1484491741 +0100
`), tag: Tag{ `), tag: Tag{
Name: "", Name: "",
ID: NewSha1(), ID: Sha1ObjectFormat.EmptyObjectID(),
Object: &Sha1Hash{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a}, Object: &Sha1Hash{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a},
Type: "commit", Type: "commit",
Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0)}, Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0)},
@ -39,7 +39,7 @@ o
ono`), tag: Tag{ ono`), tag: Tag{
Name: "", Name: "",
ID: NewSha1(), ID: Sha1ObjectFormat.EmptyObjectID(),
Object: &Sha1Hash{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc}, Object: &Sha1Hash{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc},
Type: "commit", Type: "commit",
Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0)}, Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0)},
@ -49,7 +49,7 @@ ono`), tag: Tag{
} }
for _, test := range testData { for _, test := range testData {
tag, err := parseTagData(ObjectFormatFromID(Sha1), test.data) tag, err := parseTagData(Sha1ObjectFormat, test.data)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, test.tag.ID, tag.ID) assert.EqualValues(t, test.tag.ID, tag.ID)
assert.EqualValues(t, test.tag.Object, tag.Object) assert.EqualValues(t, test.tag.Object, tag.Object)

View File

@ -9,6 +9,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
gohtml "html" gohtml "html"
"html/template"
"io" "io"
"path/filepath" "path/filepath"
"strings" "strings"
@ -55,7 +56,7 @@ func NewContext() {
} }
// Code returns a HTML version of code string with chroma syntax highlighting classes and the matched lexer name // Code returns a HTML version of code string with chroma syntax highlighting classes and the matched lexer name
func Code(fileName, language, code string) (string, string) { func Code(fileName, language, code string) (output template.HTML, lexerName string) {
NewContext() NewContext()
// diff view newline will be passed as empty, change to literal '\n' so it can be copied // diff view newline will be passed as empty, change to literal '\n' so it can be copied
@ -65,7 +66,7 @@ func Code(fileName, language, code string) (string, string) {
} }
if len(code) > sizeLimit { if len(code) > sizeLimit {
return code, "" return template.HTML(template.HTMLEscapeString(code)), ""
} }
var lexer chroma.Lexer var lexer chroma.Lexer
@ -102,13 +103,11 @@ func Code(fileName, language, code string) (string, string) {
cache.Add(fileName, lexer) cache.Add(fileName, lexer)
} }
lexerName := formatLexerName(lexer.Config().Name) return CodeFromLexer(lexer, code), formatLexerName(lexer.Config().Name)
return CodeFromLexer(lexer, code), lexerName
} }
// CodeFromLexer returns a HTML version of code string with chroma syntax highlighting classes // CodeFromLexer returns a HTML version of code string with chroma syntax highlighting classes
func CodeFromLexer(lexer chroma.Lexer, code string) string { func CodeFromLexer(lexer chroma.Lexer, code string) template.HTML {
formatter := html.New(html.WithClasses(true), formatter := html.New(html.WithClasses(true),
html.WithLineNumbers(false), html.WithLineNumbers(false),
html.PreventSurroundingPre(true), html.PreventSurroundingPre(true),
@ -120,23 +119,23 @@ func CodeFromLexer(lexer chroma.Lexer, code string) string {
iterator, err := lexer.Tokenise(nil, code) iterator, err := lexer.Tokenise(nil, code)
if err != nil { if err != nil {
log.Error("Can't tokenize code: %v", err) log.Error("Can't tokenize code: %v", err)
return code return template.HTML(template.HTMLEscapeString(code))
} }
// style not used for live site but need to pass something // style not used for live site but need to pass something
err = formatter.Format(htmlw, githubStyles, iterator) err = formatter.Format(htmlw, githubStyles, iterator)
if err != nil { if err != nil {
log.Error("Can't format code: %v", err) log.Error("Can't format code: %v", err)
return code return template.HTML(template.HTMLEscapeString(code))
} }
_ = htmlw.Flush() _ = htmlw.Flush()
// Chroma will add newlines for certain lexers in order to highlight them properly // Chroma will add newlines for certain lexers in order to highlight them properly
// Once highlighted, strip them here, so they don't cause copy/paste trouble in HTML output // Once highlighted, strip them here, so they don't cause copy/paste trouble in HTML output
return strings.TrimSuffix(htmlbuf.String(), "\n") return template.HTML(strings.TrimSuffix(htmlbuf.String(), "\n"))
} }
// File returns a slice of chroma syntax highlighted HTML lines of code and the matched lexer name // File returns a slice of chroma syntax highlighted HTML lines of code and the matched lexer name
func File(fileName, language string, code []byte) ([]string, string, error) { func File(fileName, language string, code []byte) ([]template.HTML, string, error) {
NewContext() NewContext()
if len(code) > sizeLimit { if len(code) > sizeLimit {
@ -183,14 +182,14 @@ func File(fileName, language string, code []byte) ([]string, string, error) {
tokensLines := chroma.SplitTokensIntoLines(iterator.Tokens()) tokensLines := chroma.SplitTokensIntoLines(iterator.Tokens())
htmlBuf := &bytes.Buffer{} htmlBuf := &bytes.Buffer{}
lines := make([]string, 0, len(tokensLines)) lines := make([]template.HTML, 0, len(tokensLines))
for _, tokens := range tokensLines { for _, tokens := range tokensLines {
iterator = chroma.Literator(tokens...) iterator = chroma.Literator(tokens...)
err = formatter.Format(htmlBuf, githubStyles, iterator) err = formatter.Format(htmlBuf, githubStyles, iterator)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("can't format code: %w", err) return nil, "", fmt.Errorf("can't format code: %w", err)
} }
lines = append(lines, htmlBuf.String()) lines = append(lines, template.HTML(htmlBuf.String()))
htmlBuf.Reset() htmlBuf.Reset()
} }
@ -198,9 +197,9 @@ func File(fileName, language string, code []byte) ([]string, string, error) {
} }
// PlainText returns non-highlighted HTML for code // PlainText returns non-highlighted HTML for code
func PlainText(code []byte) []string { func PlainText(code []byte) []template.HTML {
r := bufio.NewReader(bytes.NewReader(code)) r := bufio.NewReader(bytes.NewReader(code))
m := make([]string, 0, bytes.Count(code, []byte{'\n'})+1) m := make([]template.HTML, 0, bytes.Count(code, []byte{'\n'})+1)
for { for {
content, err := r.ReadString('\n') content, err := r.ReadString('\n')
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
@ -210,7 +209,7 @@ func PlainText(code []byte) []string {
if content == "" && err == io.EOF { if content == "" && err == io.EOF {
break break
} }
s := gohtml.EscapeString(content) s := template.HTML(gohtml.EscapeString(content))
m = append(m, s) m = append(m, s)
} }
return m return m

View File

@ -4,21 +4,36 @@
package highlight package highlight
import ( import (
"html/template"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func lines(s string) []string { func lines(s string) (out []template.HTML) {
return strings.Split(strings.ReplaceAll(strings.TrimSpace(s), `\n`, "\n"), "\n") // "" => [], "a" => ["a"], "a\n" => ["a\n"], "a\nb" => ["a\n", "b"] (each line always includes EOL "\n" if it exists)
out = make([]template.HTML, 0)
s = strings.ReplaceAll(strings.ReplaceAll(strings.TrimSpace(s), "\n", ""), `\n`, "\n")
for {
if p := strings.IndexByte(s, '\n'); p != -1 {
out = append(out, template.HTML(s[:p+1]))
s = s[p+1:]
} else {
break
}
}
if s != "" {
out = append(out, template.HTML(s))
}
return out
} }
func TestFile(t *testing.T) { func TestFile(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
code string code string
want []string want []template.HTML
lexerName string lexerName string
}{ }{
{ {
@ -99,10 +114,7 @@ c=2
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
out, lexerName, err := File(tt.name, "", []byte(tt.code)) out, lexerName, err := File(tt.name, "", []byte(tt.code))
assert.NoError(t, err) assert.NoError(t, err)
expected := strings.Join(tt.want, "\n") assert.EqualValues(t, tt.want, out)
actual := strings.Join(out, "\n")
assert.Equal(t, strings.Count(actual, "<span"), strings.Count(actual, "</span>"))
assert.EqualValues(t, expected, actual)
assert.Equal(t, tt.lexerName, lexerName) assert.Equal(t, tt.lexerName, lexerName)
}) })
} }
@ -112,7 +124,7 @@ func TestPlainText(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
code string code string
want []string want []template.HTML
}{ }{
{ {
name: "empty.py", name: "empty.py",
@ -165,9 +177,7 @@ c=2`),
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
out := PlainText([]byte(tt.code)) out := PlainText([]byte(tt.code))
expected := strings.Join(tt.want, "\n") assert.EqualValues(t, tt.want, out)
actual := strings.Join(out, "\n")
assert.EqualValues(t, expected, actual)
}) })
} }
} }

View File

@ -6,6 +6,7 @@ package code
import ( import (
"bytes" "bytes"
"context" "context"
"html/template"
"strings" "strings"
"code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/highlight"
@ -22,7 +23,7 @@ type Result struct {
Language string Language string
Color string Color string
LineNumbers []int LineNumbers []int
FormattedLines string FormattedLines template.HTML
} }
type SearchResultLanguages = internal.SearchResultLanguages type SearchResultLanguages = internal.SearchResultLanguages

View File

@ -87,7 +87,7 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
} }
lexer = chroma.Coalesce(lexer) lexer = chroma.Coalesce(lexer)
if _, err := w.WriteString(highlight.CodeFromLexer(lexer, source)); err != nil { if _, err := w.WriteString(string(highlight.CodeFromLexer(lexer, source))); err != nil {
return "" return ""
} }
} }

View File

@ -144,7 +144,7 @@ func TestCommitToPushCommit(t *testing.T) {
When: now, When: now,
} }
const hexString = "0123456789abcdef0123456789abcdef01234567" const hexString = "0123456789abcdef0123456789abcdef01234567"
sha1, err := git.IDFromString(hexString) sha1, err := git.NewIDFromString(hexString)
assert.NoError(t, err) assert.NoError(t, err)
pushCommit := CommitToPushCommit(&git.Commit{ pushCommit := CommitToPushCommit(&git.Commit{
ID: sha1, ID: sha1,
@ -169,12 +169,11 @@ func TestListToPushCommits(t *testing.T) {
When: now, When: now,
} }
hashType := git.ObjectFormatFromID(git.Sha1)
const hexString1 = "0123456789abcdef0123456789abcdef01234567" const hexString1 = "0123456789abcdef0123456789abcdef01234567"
hash1, err := hashType.NewIDFromString(hexString1) hash1, err := git.NewIDFromString(hexString1)
assert.NoError(t, err) assert.NoError(t, err)
const hexString2 = "fedcba9876543210fedcba9876543210fedcba98" const hexString2 = "fedcba9876543210fedcba9876543210fedcba98"
hash2, err := hashType.NewIDFromString(hexString2) hash2, err := git.NewIDFromString(hexString2)
assert.NoError(t, err) assert.NoError(t, err)
l := []*git.Commit{ l := []*git.Commit{

View File

@ -224,7 +224,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
} }
// FIXME: fix the hash // FIXME: fix the hash
if err := git.InitRepository(ctx, tmpDir, false, git.ObjectFormatFromID(git.Sha1)); err != nil { if err := git.InitRepository(ctx, tmpDir, false, git.Sha1ObjectFormat.Name()); err != nil {
return err return err
} }
@ -358,7 +358,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
} }
// FIXME - fix the hash // FIXME - fix the hash
if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, git.ObjectFormatFromID(git.Sha1)); err != nil { if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, git.Sha1ObjectFormat.Name()); err != nil {
return generateRepo, err return generateRepo, err
} }

View File

@ -188,7 +188,7 @@ func InitRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
return nil return nil
} }
func CheckInitRepository(ctx context.Context, owner, name string, objectFormat git.ObjectFormat) (err error) { func CheckInitRepository(ctx context.Context, owner, name, objectFormatName string) (err error) {
// Somehow the directory could exist. // Somehow the directory could exist.
repoPath := repo_model.RepoPath(owner, name) repoPath := repo_model.RepoPath(owner, name)
isExist, err := util.IsExist(repoPath) isExist, err := util.IsExist(repoPath)
@ -204,7 +204,7 @@ func CheckInitRepository(ctx context.Context, owner, name string, objectFormat g
} }
// Init git bare new repository. // Init git bare new repository.
if err = git.InitRepository(ctx, repoPath, true, objectFormat); err != nil { if err = git.InitRepository(ctx, repoPath, true, objectFormatName); err != nil {
return fmt.Errorf("git.InitRepository: %w", err) return fmt.Errorf("git.InitRepository: %w", err)
} else if err = CreateDelegateHooks(repoPath); err != nil { } else if err = CreateDelegateHooks(repoPath); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err) return fmt.Errorf("createDelegateHooks: %w", err)

View File

@ -20,13 +20,13 @@ type PushUpdateOptions struct {
// IsNewRef return true if it's a first-time push to a branch, tag or etc. // IsNewRef return true if it's a first-time push to a branch, tag or etc.
func (opts *PushUpdateOptions) IsNewRef() bool { func (opts *PushUpdateOptions) IsNewRef() bool {
commitID, err := git.IDFromString(opts.OldCommitID) commitID, err := git.NewIDFromString(opts.OldCommitID)
return err == nil && commitID.IsZero() return err == nil && commitID.IsZero()
} }
// IsDelRef return true if it's a deletion to a branch or tag // IsDelRef return true if it's a deletion to a branch or tag
func (opts *PushUpdateOptions) IsDelRef() bool { func (opts *PushUpdateOptions) IsDelRef() bool {
commitID, err := git.IDFromString(opts.NewCommitID) commitID, err := git.NewIDFromString(opts.NewCommitID)
return err == nil && commitID.IsZero() return err == nil && commitID.IsZero()
} }

View File

@ -12,7 +12,6 @@ import (
// Cache represents cache settings // Cache represents cache settings
type Cache struct { type Cache struct {
Enabled bool
Adapter string Adapter string
Interval int Interval int
Conn string Conn string
@ -24,23 +23,19 @@ var CacheService = struct {
Cache `ini:"cache"` Cache `ini:"cache"`
LastCommit struct { LastCommit struct {
Enabled bool
TTL time.Duration `ini:"ITEM_TTL"` TTL time.Duration `ini:"ITEM_TTL"`
CommitsCount int64 CommitsCount int64
} `ini:"cache.last_commit"` } `ini:"cache.last_commit"`
}{ }{
Cache: Cache{ Cache: Cache{
Enabled: true,
Adapter: "memory", Adapter: "memory",
Interval: 60, Interval: 60,
TTL: 16 * time.Hour, TTL: 16 * time.Hour,
}, },
LastCommit: struct { LastCommit: struct {
Enabled bool
TTL time.Duration `ini:"ITEM_TTL"` TTL time.Duration `ini:"ITEM_TTL"`
CommitsCount int64 CommitsCount int64
}{ }{
Enabled: true,
TTL: 8760 * time.Hour, TTL: 8760 * time.Hour,
CommitsCount: 1000, CommitsCount: 1000,
}, },
@ -65,30 +60,12 @@ func loadCacheFrom(rootCfg ConfigProvider) {
if CacheService.Conn == "" { if CacheService.Conn == "" {
CacheService.Conn = "50000" CacheService.Conn = "50000"
} }
case "": // disable cache
CacheService.Enabled = false
default: default:
log.Fatal("Unknown cache adapter: %s", CacheService.Adapter) log.Fatal("Unknown cache adapter: %s", CacheService.Adapter)
} }
if CacheService.Enabled {
log.Info("Cache Service Enabled")
} else {
log.Warn("Cache Service Disabled so that captcha disabled too")
// captcha depends on cache service
Service.EnableCaptcha = false
}
sec = rootCfg.Section("cache.last_commit") sec = rootCfg.Section("cache.last_commit")
if !CacheService.Enabled {
CacheService.LastCommit.Enabled = false
}
CacheService.LastCommit.CommitsCount = sec.Key("COMMITS_COUNT").MustInt64(1000) CacheService.LastCommit.CommitsCount = sec.Key("COMMITS_COUNT").MustInt64(1000)
if CacheService.LastCommit.Enabled {
log.Info("Last Commit Cache Service Enabled")
}
} }
// TTLSeconds returns the TTLSeconds or unix timestamp for memcache // TTLSeconds returns the TTLSeconds or unix timestamp for memcache

View File

@ -35,6 +35,8 @@ var UI = struct {
OnlyShowRelevantRepos bool OnlyShowRelevantRepos bool
ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"` ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"`
AmbiguousUnicodeDetection bool
Notification struct { Notification struct {
MinTimeout time.Duration MinTimeout time.Duration
TimeoutStep time.Duration TimeoutStep time.Duration
@ -82,6 +84,9 @@ var UI = struct {
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`}, CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"}, CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
AmbiguousUnicodeDetection: true,
Notification: struct { Notification: struct {
MinTimeout time.Duration MinTimeout time.Duration
TimeoutStep time.Duration TimeoutStep time.Duration

View File

@ -16,8 +16,7 @@ type CreateUserOption struct {
// required: true // required: true
// swagger:strfmt email // swagger:strfmt email
Email string `json:"email" binding:"Required;Email;MaxSize(254)"` Email string `json:"email" binding:"Required;Email;MaxSize(254)"`
// required: true Password string `json:"password" binding:"MaxSize(255)"`
Password string `json:"password" binding:"Required;MaxSize(255)"`
MustChangePassword *bool `json:"must_change_password"` MustChangePassword *bool `json:"must_change_password"`
SendNotify bool `json:"send_notify"` SendNotify bool `json:"send_notify"`
Restricted *bool `json:"restricted"` Restricted *bool `json:"restricted"`

View File

@ -3,7 +3,7 @@
package util package util
import "github.com/yuin/goldmark/util" import "unsafe"
func isSnakeCaseUpper(c byte) bool { func isSnakeCaseUpper(c byte) bool {
return 'A' <= c && c <= 'Z' return 'A' <= c && c <= 'Z'
@ -83,5 +83,15 @@ func ToSnakeCase(input string) string {
} }
} }
} }
return util.BytesToReadOnlyString(res) return UnsafeBytesToString(res)
}
// UnsafeBytesToString uses Go's unsafe package to convert a byte slice to a string.
// TODO: replace all "goldmark/util.BytesToReadOnlyString" with this official approach
func UnsafeBytesToString(b []byte) string {
return unsafe.String(unsafe.SliceData(b), len(b))
}
func UnsafeStringToBytes(s string) []byte {
return unsafe.Slice(unsafe.StringData(s), len(s))
} }

View File

@ -3090,7 +3090,6 @@ config.enable_openid_signin = Enable OpenID Sign-In
config.show_registration_button = Show Register Button config.show_registration_button = Show Register Button
config.require_sign_in_view = Require Sign-In to View Pages config.require_sign_in_view = Require Sign-In to View Pages
config.mail_notify = Enable Email Notifications config.mail_notify = Enable Email Notifications
config.disable_key_size_check = Disable Minimum Key Size Check
config.enable_captcha = Enable CAPTCHA config.enable_captcha = Enable CAPTCHA
config.active_code_lives = Active Code Lives config.active_code_lives = Active Code Lives
config.reset_password_code_lives = Recover Account Code Expiry Time config.reset_password_code_lives = Recover Account Code Expiry Time
@ -3536,7 +3535,7 @@ runs.commit = Commit
runs.scheduled = Scheduled runs.scheduled = Scheduled
runs.pushed_by = pushed by runs.pushed_by = pushed by
runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s
runs.no_matching_runner_helper = No matching runner: %s runs.no_matching_online_runner_helper = No matching online runner with label: %s
runs.actor = Actor runs.actor = Actor
runs.status = Status runs.status = Status
runs.actors_no_select = All actors runs.actors_no_select = All actors

View File

@ -17,6 +17,7 @@ template=テンプレート
language=言語 language=言語
notifications=通知 notifications=通知
active_stopwatch=進行中のタイムトラッカー active_stopwatch=進行中のタイムトラッカー
tracked_time_summary=イシューリストのフィルタに基づき集計したトラッキング時間
create_new=作成… create_new=作成…
user_profile_and_more=プロフィールと設定… user_profile_and_more=プロフィールと設定…
signed_in_as=サインイン済み signed_in_as=サインイン済み
@ -359,6 +360,7 @@ disable_register_prompt=登録は無効になっています。 サイト管理
disable_register_mail=登録でのメール確認は無効になっています。 disable_register_mail=登録でのメール確認は無効になっています。
manual_activation_only=アクティベーションを完了するにはサイト管理者に連絡してください。 manual_activation_only=アクティベーションを完了するにはサイト管理者に連絡してください。
remember_me=このデバイスで自動サインイン remember_me=このデバイスで自動サインイン
remember_me.compromised=ログイントークンはもう有効ではなく、アカウントが侵害されたことを示している可能性があります。 異常なアクティビティがないかアカウントを確認してください。
forgot_password_title=パスワードを忘れた forgot_password_title=パスワードを忘れた
forgot_password=パスワードをお忘れですか? forgot_password=パスワードをお忘れですか?
sign_up_now=アカウントが必要ですか? 今すぐ登録しましょう。 sign_up_now=アカウントが必要ですか? 今すぐ登録しましょう。
@ -623,11 +625,11 @@ applications=アプリケーション
orgs=組織の管理 orgs=組織の管理
repos=リポジトリ repos=リポジトリ
delete=アカウントを削除 delete=アカウントを削除
twofa=2要素認証 twofa=2要素認証 (TOTP)
account_link=連携アカウント account_link=連携アカウント
organization=組織 organization=組織
uid=UID uid=UID
webauthn=セキュリティキー webauthn=2要素認証 (セキュリティキー)
public_profile=公開プロフィール public_profile=公開プロフィール
biography_placeholder=自己紹介してください!(Markdownを使うことができます) biography_placeholder=自己紹介してください!(Markdownを使うことができます)
@ -861,22 +863,23 @@ revoke_oauth2_grant=アクセス権の取り消し
revoke_oauth2_grant_description=このサードパーティ アプリケーションのアクセス権を取り消し、アプリケーションがあなたのデータへアクセスすることを防ぎます。 続行しますか? revoke_oauth2_grant_description=このサードパーティ アプリケーションのアクセス権を取り消し、アプリケーションがあなたのデータへアクセスすることを防ぎます。 続行しますか?
revoke_oauth2_grant_success=アクセス権を取り消しました。 revoke_oauth2_grant_success=アクセス権を取り消しました。
twofa_desc=2要素認証はアカウントのセキュリティを強化します。 twofa_desc=パスワードの盗難からアカウントを守るために、スマートフォンや他のデバイスを使用して、時間ベースのワンタイムパスワード("TOTP")を受け取ることができます。
twofa_recovery_tip=デバイスを紛失した場合は、一回限りのリカバリキーを使用してアカウントへのアクセスを回復することができます。
twofa_is_enrolled=このアカウントは2要素認証が<strong>有効</strong>になっています。 twofa_is_enrolled=このアカウントは2要素認証が<strong>有効</strong>になっています。
twofa_not_enrolled=このアカウントは2要素認証が設定されていません。 twofa_not_enrolled=このアカウントは2要素認証が設定されていません。
twofa_disable=2要素認証を無効にする twofa_disable=2要素認証を無効にする
twofa_scratch_token_regenerate=スクラッチトークンを再生成 twofa_scratch_token_regenerate=一回限りのリカバリキーを再生成
twofa_scratch_token_regenerated=あなたのスクラッチトークンは %s になりました。 安全な場所に保管してください。 二度と表示されません。 twofa_scratch_token_regenerated=あなたの一回限りのリカバリキーは %s になりました。 安全な場所に保管してください。 これは二度と表示されません。
twofa_enroll=2要素認証の開始 twofa_enroll=2要素認証の開始
twofa_disable_note=2要素認証は必要に応じて無効にできます。 twofa_disable_note=2要素認証は必要に応じて無効にできます。
twofa_disable_desc=2要素認証を無効にするとアカウントのセキュリティが低下します。 続行しますか? twofa_disable_desc=2要素認証を無効にするとアカウントのセキュリティが低下します。 続行しますか?
regenerate_scratch_token_desc=スクラッチトークンを紛失した場合やサインインで使用済みとなった場合は、ここでリセットできます。 regenerate_scratch_token_desc=リカバリキーを紛失した場合や、すでにサインインに使用済みの場合は、ここでリセットできます。
twofa_disabled=2要素認証を無効にしました。 twofa_disabled=2要素認証を無効にしました。
scan_this_image=この画像を認証アプリケーションで読み取ってください。 scan_this_image=この画像を認証アプリケーションで読み取ってください。
or_enter_secret=またはシークレット文字列を入力: %s or_enter_secret=またはシークレット文字列を入力: %s
then_enter_passcode=次に、アプリケーションに表示されているパスコードを入力します。 then_enter_passcode=次に、アプリケーションに表示されているパスコードを入力します。
passcode_invalid=パスコードが間違っています。 再度お試しください。 passcode_invalid=パスコードが間違っています。 再度お試しください。
twofa_enrolled=あなたのアカウントに2要素認証が設定されました。 スクラッチトークン (%s) は一度しか表示しませんので安全な場所に保存してください! twofa_enrolled=あなたのアカウントは正常に登録されました。 一回限りのリカバリキー (%s) は安全な場所に保存してください。 これは二度と表示されません。
twofa_failed_get_secret=シークレットが取得できません。 twofa_failed_get_secret=シークレットが取得できません。
webauthn_desc=セキュリティキーは暗号化キーを内蔵するハードウェア ・ デバイスです。 2要素認証に使用できます。 セキュリティキーは<a rel="noreferrer" target="_blank" href="https://w3c.github.io/webauthn/#webauthn-authenticator">WebAuthn Authenticator</a>規格をサポートしている必要があります。 webauthn_desc=セキュリティキーは暗号化キーを内蔵するハードウェア ・ デバイスです。 2要素認証に使用できます。 セキュリティキーは<a rel="noreferrer" target="_blank" href="https://w3c.github.io/webauthn/#webauthn-authenticator">WebAuthn Authenticator</a>規格をサポートしている必要があります。
@ -884,6 +887,8 @@ webauthn_register_key=セキュリティキーを追加
webauthn_nickname=ニックネーム webauthn_nickname=ニックネーム
webauthn_delete_key=セキュリティキーの登録解除 webauthn_delete_key=セキュリティキーの登録解除
webauthn_delete_key_desc=セキュリティキーの登録を解除すると、今後そのセキュリティキーでサインインすることはできなくなります。 続行しますか? webauthn_delete_key_desc=セキュリティキーの登録を解除すると、今後そのセキュリティキーでサインインすることはできなくなります。 続行しますか?
webauthn_key_loss_warning=セキュリティキーを紛失すると、アカウントへのアクセスを失います。
webauthn_alternative_tip=もうひとつ別の認証方法も設定しておくと良いでしょう。
manage_account_links=連携アカウントの管理 manage_account_links=連携アカウントの管理
manage_account_links_desc=これらの外部アカウントがGiteaアカウントと連携されています。 manage_account_links_desc=これらの外部アカウントがGiteaアカウントと連携されています。
@ -920,6 +925,7 @@ visibility.private=プライベート
visibility.private_tooltip=あなたが参加した組織のメンバーのみに表示されます visibility.private_tooltip=あなたが参加した組織のメンバーのみに表示されます
[repo] [repo]
new_repo_helper=リポジトリには、プロジェクトのすべてのファイルとリビジョン履歴が入ります。 すでにほかの場所でホストしていますか? <a href="%s">リポジトリを移行</a> もどうぞ。
owner=オーナー owner=オーナー
owner_helper=リポジトリ数の上限により、一部の組織はドロップダウンに表示されない場合があります。 owner_helper=リポジトリ数の上限により、一部の組織はドロップダウンに表示されない場合があります。
repo_name=リポジトリ名 repo_name=リポジトリ名
@ -1782,6 +1788,8 @@ pulls.status_checks_failure=失敗したステータスチェックがありま
pulls.status_checks_error=ステータスチェックによりエラーが出ています pulls.status_checks_error=ステータスチェックによりエラーが出ています
pulls.status_checks_requested=必須 pulls.status_checks_requested=必須
pulls.status_checks_details=詳細 pulls.status_checks_details=詳細
pulls.status_checks_hide_all=すべてのチェックを隠す
pulls.status_checks_show_all=すべてのチェックを表示
pulls.update_branch=マージでブランチを更新 pulls.update_branch=マージでブランチを更新
pulls.update_branch_rebase=リベースでブランチを更新 pulls.update_branch_rebase=リベースでブランチを更新
pulls.update_branch_success=ブランチの更新が成功しました pulls.update_branch_success=ブランチの更新が成功しました
@ -1790,6 +1798,11 @@ pulls.outdated_with_base_branch=このブランチはベースブランチに対
pulls.close=プルリクエストをクローズ pulls.close=プルリクエストをクローズ
pulls.closed_at=`がプルリクエストをクローズ <a id="%[1]s" href="#%[1]s">%[2]s</a>` pulls.closed_at=`がプルリクエストをクローズ <a id="%[1]s" href="#%[1]s">%[2]s</a>`
pulls.reopened_at=`がプルリクエストを再オープン <a id="%[1]s" href="#%[1]s">%[2]s</a>` pulls.reopened_at=`がプルリクエストを再オープン <a id="%[1]s" href="#%[1]s">%[2]s</a>`
pulls.cmd_instruction_hint=`<a class="show-instruction">コマンドラインの手順</a>を表示します。`
pulls.cmd_instruction_checkout_title=チェックアウト
pulls.cmd_instruction_checkout_desc=プロジェクトリポジトリから新しいブランチをチェックアウトし、変更内容をテストします。
pulls.cmd_instruction_merge_title=マージ
pulls.cmd_instruction_merge_desc=変更内容をマージして、Giteaに反映します。
pulls.clear_merge_message=マージメッセージをクリア pulls.clear_merge_message=マージメッセージをクリア
pulls.clear_merge_message_hint=マージメッセージのクリアは、コミットメッセージの除去だけを行います。 生成されたGitトレーラー("Co-Authored-By …" 等)はそのまま残ります。 pulls.clear_merge_message_hint=マージメッセージのクリアは、コミットメッセージの除去だけを行います。 生成されたGitトレーラー("Co-Authored-By …" 等)はそのまま残ります。
@ -2301,6 +2314,7 @@ settings.dismiss_stale_approvals_desc=プルリクエストの内容を変える
settings.require_signed_commits=コミット署名必須 settings.require_signed_commits=コミット署名必須
settings.require_signed_commits_desc=署名されていない場合、または署名が検証できなかった場合は、このブランチへのプッシュを拒否します。 settings.require_signed_commits_desc=署名されていない場合、または署名が検証できなかった場合は、このブランチへのプッシュを拒否します。
settings.protect_branch_name_pattern=保護ブランチ名のパターン settings.protect_branch_name_pattern=保護ブランチ名のパターン
settings.protect_branch_name_pattern_desc=保護ブランチ名のパターン。書き方については <a href="https://github.com/gobwas/glob">ドキュメント</a> を参照してください。例: main, release/**
settings.protect_patterns=パターン settings.protect_patterns=パターン
settings.protect_protected_file_patterns=保護されるファイルのパターン (セミコロン';'で区切る): settings.protect_protected_file_patterns=保護されるファイルのパターン (セミコロン';'で区切る):
settings.protect_protected_file_patterns_desc=保護されたファイルは、このブランチにファイルを追加・編集・削除する権限を持つユーザーであっても、直接変更することができなくなります。 セミコロン(';')で区切って複数のパターンを指定できます。 パターンの文法については <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> を参照してください。 例: <code>.drone.yml</code>, <code>/docs/**/*.txt</code> settings.protect_protected_file_patterns_desc=保護されたファイルは、このブランチにファイルを追加・編集・削除する権限を持つユーザーであっても、直接変更することができなくなります。 セミコロン(';')で区切って複数のパターンを指定できます。 パターンの文法については <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> を参照してください。 例: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>
@ -2846,6 +2860,7 @@ emails.updated=メール設定を更新しました
emails.not_updated=メール設定の更新に失敗しました: %v emails.not_updated=メール設定の更新に失敗しました: %v
emails.duplicate_active=メールアドレスは別のユーザーが既に使用中です。 emails.duplicate_active=メールアドレスは別のユーザーが既に使用中です。
emails.change_email_header=メール設定の更新 emails.change_email_header=メール設定の更新
emails.change_email_text=このメールアドレスで更新してもよろしいですか?
orgs.org_manage_panel=組織の管理 orgs.org_manage_panel=組織の管理
orgs.name=名称 orgs.name=名称
@ -2870,6 +2885,7 @@ packages.package_manage_panel=パッケージ管理
packages.total_size=合計サイズ: %s packages.total_size=合計サイズ: %s
packages.unreferenced_size=非参照サイズ: %s packages.unreferenced_size=非参照サイズ: %s
packages.cleanup=期限切れデータを掃除する packages.cleanup=期限切れデータを掃除する
packages.cleanup.success=期限切れのデータを正常にクリーンアップしました
packages.owner=オーナー packages.owner=オーナー
packages.creator=作成者 packages.creator=作成者
packages.name=名前 packages.name=名前
@ -3441,7 +3457,7 @@ owner.settings.chef.keypair.description=Chefレジストリの認証にはキー
[secrets] [secrets]
secrets=シークレット secrets=シークレット
description=シークレットは特定のActionsに渡されます。 それ以外で読み出されることはありません。 description=シークレットは特定のActionsに渡されます。 それ以外で読み出されることはありません。
none=まだシークレットはありません。 none=シークレットはまだありません。
creation=シークレットを追加 creation=シークレットを追加
creation.name_placeholder=大文字小文字の区別なし、英数字とアンダースコアのみ、GITEA_ や GITHUB_ で始まるものは不可 creation.name_placeholder=大文字小文字の区別なし、英数字とアンダースコアのみ、GITEA_ や GITHUB_ で始まるものは不可
creation.value_placeholder=内容を入力してください。前後の空白は除去されます。 creation.value_placeholder=内容を入力してください。前後の空白は除去されます。
@ -3516,6 +3532,7 @@ runs.actors_no_select=すべてのアクター
runs.status_no_select=すべてのステータス runs.status_no_select=すべてのステータス
runs.no_results=一致する結果はありません。 runs.no_results=一致する結果はありません。
runs.no_runs=ワークフローはまだ実行されていません。 runs.no_runs=ワークフローはまだ実行されていません。
runs.empty_commit_message=(空のコミットメッセージ)
workflow.disable=ワークフローを無効にする workflow.disable=ワークフローを無効にする
workflow.disable_success=ワークフロー '%s' が無効になりました。 workflow.disable_success=ワークフロー '%s' が無効になりました。

View File

@ -93,11 +93,20 @@ func CreateUser(ctx *context.APIContext) {
if ctx.Written() { if ctx.Written() {
return return
} }
if u.LoginType == auth.Plain {
if len(form.Password) < setting.MinPasswordLength {
err := errors.New("PasswordIsRequired")
ctx.Error(http.StatusBadRequest, "PasswordIsRequired", err)
return
}
if !password.IsComplexEnough(form.Password) { if !password.IsComplexEnough(form.Password) {
err := errors.New("PasswordComplexity") err := errors.New("PasswordComplexity")
ctx.Error(http.StatusBadRequest, "PasswordComplexity", err) ctx.Error(http.StatusBadRequest, "PasswordComplexity", err)
return return
} }
pwned, err := password.IsPwned(ctx, form.Password) pwned, err := password.IsPwned(ctx, form.Password)
if pwned { if pwned {
if err != nil { if err != nil {
@ -106,6 +115,7 @@ func CreateUser(ctx *context.APIContext) {
ctx.Error(http.StatusBadRequest, "PasswordPwned", errors.New("PasswordPwned")) ctx.Error(http.StatusBadRequest, "PasswordPwned", errors.New("PasswordPwned"))
return return
} }
}
overwriteDefault := &user_model.CreateUserOverwriteOptions{ overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue, IsActive: util.OptionalBoolTrue,

View File

@ -29,10 +29,9 @@ func NodeInfo(ctx *context.APIContext) {
nodeInfoUsage := structs.NodeInfoUsage{} nodeInfoUsage := structs.NodeInfoUsage{}
if setting.Federation.ShareUserStatistics { if setting.Federation.ShareUserStatistics {
cached := false var cached bool
if setting.CacheService.Enabled {
nodeInfoUsage, cached = ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage) nodeInfoUsage, cached = ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage)
}
if !cached { if !cached {
usersTotal := int(user_model.CountUsers(ctx, nil)) usersTotal := int(user_model.CountUsers(ctx, nil))
now := time.Now() now := time.Now()
@ -53,14 +52,13 @@ func NodeInfo(ctx *context.APIContext) {
LocalPosts: int(allIssues), LocalPosts: int(allIssues),
LocalComments: int(allComments), LocalComments: int(allComments),
} }
if setting.CacheService.Enabled {
if err := ctx.Cache.Put(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil { if err := ctx.Cache.Put(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
} }
} }
} }
}
nodeInfo := &structs.NodeInfo{ nodeInfo := &structs.NodeInfo{
Version: "2.1", Version: "2.1",

View File

@ -253,7 +253,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
DefaultBranch: opt.DefaultBranch, DefaultBranch: opt.DefaultBranch,
TrustModel: repo_model.ToTrustModel(opt.TrustModel), TrustModel: repo_model.ToTrustModel(opt.TrustModel),
IsTemplate: opt.Template, IsTemplate: opt.Template,
ObjectFormat: git.ObjectFormatFromID(git.Sha1), ObjectFormatName: git.Sha1ObjectFormat.Name(),
}) })
if err != nil { if err != nil {
if repo_model.IsErrRepoAlreadyExist(err) { if repo_model.IsErrRepoAlreadyExist(err) {

View File

@ -73,7 +73,7 @@ func searchRefCommitByType(ctx *context.APIContext, refType, filter string) (str
func ConvertToObjectID(ctx gocontext.Context, repo *context.Repository, commitID string) (git.ObjectID, error) { func ConvertToObjectID(ctx gocontext.Context, repo *context.Repository, commitID string) (git.ObjectID, error) {
objectFormat, _ := repo.GitRepo.GetObjectFormat() objectFormat, _ := repo.GitRepo.GetObjectFormat()
if len(commitID) == objectFormat.FullLength() && objectFormat.IsValid(commitID) { if len(commitID) == objectFormat.FullLength() && objectFormat.IsValid(commitID) {
sha, err := objectFormat.NewIDFromString(commitID) sha, err := git.NewIDFromString(commitID)
if err == nil { if err == nil {
return sha, nil return sha, nil
} }
@ -81,7 +81,7 @@ func ConvertToObjectID(ctx gocontext.Context, repo *context.Repository, commitID
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.Repository.RepoPath()) gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.Repository.RepoPath())
if err != nil { if err != nil {
return objectFormat.Empty(), fmt.Errorf("RepositoryFromContextOrOpen: %w", err) return objectFormat.EmptyObjectID(), fmt.Errorf("RepositoryFromContextOrOpen: %w", err)
} }
defer closer.Close() defer closer.Close()

View File

@ -118,7 +118,7 @@ func InitWebInstalled(ctx context.Context) {
mustInit(storage.Init) mustInit(storage.Init)
mailer.NewContext(ctx) mailer.NewContext(ctx)
mustInit(cache.NewContext) mustInit(cache.Init)
mustInit(feed_service.Init) mustInit(feed_service.Init)
mustInit(uinotification.Init) mustInit(uinotification.Init)
mustInitCtx(ctx, archiver.Init) mustInitCtx(ctx, archiver.Init)

View File

@ -147,7 +147,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
gitRepo := ctx.Repo.GitRepo gitRepo := ctx.Repo.GitRepo
objectFormat, _ := gitRepo.GetObjectFormat() objectFormat, _ := gitRepo.GetObjectFormat()
if branchName == repo.DefaultBranch && newCommitID == objectFormat.Empty().String() { if branchName == repo.DefaultBranch && newCommitID == objectFormat.EmptyObjectID().String() {
log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo) log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{ ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName), UserMsg: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName),
@ -175,7 +175,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
// First of all we need to enforce absolutely: // First of all we need to enforce absolutely:
// //
// 1. Detect and prevent deletion of the branch // 1. Detect and prevent deletion of the branch
if newCommitID == objectFormat.Empty().String() { if newCommitID == objectFormat.EmptyObjectID().String() {
log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo) log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{ ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is protected from deletion", branchName), UserMsg: fmt.Sprintf("branch %s is protected from deletion", branchName),
@ -186,7 +186,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
isForcePush := false isForcePush := false
// 2. Disallow force pushes to protected branches // 2. Disallow force pushes to protected branches
if oldCommitID != objectFormat.Empty().String() { if oldCommitID != objectFormat.EmptyObjectID().String() {
output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1").AddDynamicArguments(oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env}) output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1").AddDynamicArguments(oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env})
if err != nil { if err != nil {
log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err) log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err)

View File

@ -30,7 +30,7 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
var command *git.Command var command *git.Command
objectFormat, _ := repo.GetObjectFormat() objectFormat, _ := repo.GetObjectFormat()
if oldCommitID == objectFormat.Empty().String() { if oldCommitID == objectFormat.EmptyObjectID().String() {
// When creating a new branch, the oldCommitID is empty, by using "newCommitID --not --all": // When creating a new branch, the oldCommitID is empty, by using "newCommitID --not --all":
// List commits that are reachable by following the newCommitID, exclude "all" existing heads/tags commits // List commits that are reachable by following the newCommitID, exclude "all" existing heads/tags commits
// So, it only lists the new commits received, doesn't list the commits already present in the receiving repository // So, it only lists the new commits received, doesn't list the commits already present in the receiving repository
@ -83,8 +83,8 @@ func readAndVerifyCommit(sha string, repo *git.Repository, env []string) error {
_ = stdoutReader.Close() _ = stdoutReader.Close()
_ = stdoutWriter.Close() _ = stdoutWriter.Close()
}() }()
objectFormat, _ := repo.GetObjectFormat()
commitID := objectFormat.MustIDFromString(sha) commitID := git.MustIDFromString(sha)
return git.NewCommand(repo.Ctx, "cat-file", "commit").AddDynamicArguments(sha). return git.NewCommand(repo.Ctx, "cat-file", "commit").AddDynamicArguments(sha).
Run(&git.RunOpts{ Run(&git.RunOpts{

View File

@ -30,9 +30,9 @@ func TestVerifyCommits(t *testing.T) {
verified bool verified bool
}{ }{
{"72920278f2f999e3005801e5d5b8ab8139d3641c", "d766f2917716d45be24bfa968b8409544941be32", true}, {"72920278f2f999e3005801e5d5b8ab8139d3641c", "d766f2917716d45be24bfa968b8409544941be32", true},
{objectFormat.Empty().String(), "93eac826f6188f34646cea81bf426aa5ba7d3bfe", true}, // New branch with verified commit {objectFormat.EmptyObjectID().String(), "93eac826f6188f34646cea81bf426aa5ba7d3bfe", true}, // New branch with verified commit
{"9779d17a04f1e2640583d35703c62460b2d86e0a", "72920278f2f999e3005801e5d5b8ab8139d3641c", false}, {"9779d17a04f1e2640583d35703c62460b2d86e0a", "72920278f2f999e3005801e5d5b8ab8139d3641c", false},
{objectFormat.Empty().String(), "9ce3f779ae33f31fce17fac3c512047b75d7498b", false}, // New branch with unverified commit {objectFormat.EmptyObjectID().String(), "9ce3f779ae33f31fce17fac3c512047b75d7498b", false}, // New branch with unverified commit
} }
for _, tc := range testCases { for _, tc := range testCases {

View File

@ -622,11 +622,9 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale) ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
ctx.HTML(http.StatusOK, TplActivate) ctx.HTML(http.StatusOK, TplActivate)
if setting.CacheService.Enabled {
if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
log.Error("Set cache(MailResendLimit) fail: %v", err) log.Error("Set cache(MailResendLimit) fail: %v", err)
} }
}
return false return false
} }
@ -645,18 +643,16 @@ func Activate(ctx *context.Context) {
} }
// Resend confirmation email. // Resend confirmation email.
if setting.Service.RegisterEmailConfirm { if setting.Service.RegisterEmailConfirm {
if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) { if ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName) {
ctx.Data["ResendLimited"] = true ctx.Data["ResendLimited"] = true
} else { } else {
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale) ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer) mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer)
if setting.CacheService.Enabled {
if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil { if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
log.Error("Set cache(MailResendLimit) fail: %v", err) log.Error("Set cache(MailResendLimit) fail: %v", err)
} }
} }
}
} else { } else {
ctx.Data["ServiceNotEnabled"] = true ctx.Data["ServiceNotEnabled"] = true
} }
@ -789,7 +785,7 @@ func ActivateEmail(ctx *context.Context) {
if u, err := user_model.GetUserByID(ctx, email.UID); err != nil { if u, err := user_model.GetUserByID(ctx, email.UID); err != nil {
log.Warn("GetUserByID: %d", email.UID) log.Warn("GetUserByID: %d", email.UID)
} else if setting.CacheService.Enabled { } else {
// Allow user to validate more emails // Allow user to validate more emails
_ = ctx.Cache.Delete("MailResendLimit_" + u.LowerName) _ = ctx.Cache.Delete("MailResendLimit_" + u.LowerName)
} }

View File

@ -79,7 +79,7 @@ func ForgotPasswdPost(ctx *context.Context) {
return return
} }
if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+u.LowerName) { if ctx.Cache.IsExist("MailResendLimit_" + u.LowerName) {
ctx.Data["ResendLimited"] = true ctx.Data["ResendLimited"] = true
ctx.HTML(http.StatusOK, tplForgotPassword) ctx.HTML(http.StatusOK, tplForgotPassword)
return return
@ -87,11 +87,9 @@ func ForgotPasswdPost(ctx *context.Context) {
mailer.SendResetPasswordMail(u) mailer.SendResetPasswordMail(u)
if setting.CacheService.Enabled {
if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
log.Error("Set cache(MailResendLimit) fail: %v", err) log.Error("Set cache(MailResendLimit) fail: %v", err)
} }
}
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale) ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale)
ctx.Data["IsResetSent"] = true ctx.Data["IsResetSent"] = true

View File

@ -121,10 +121,6 @@ func checkDatabase(ctx context.Context, checks checks) status {
// cache checks gitea cache status // cache checks gitea cache status
func checkCache(checks checks) status { func checkCache(checks checks) status {
if !setting.CacheService.Enabled {
return pass
}
st := componentStatus{} st := componentStatus{}
if err := cache.GetCache().Ping(); err != nil { if err := cache.GetCache().Ping(); err != nil {
st.Status = fail st.Status = fail

View File

@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/web/repo" "code.gitea.io/gitea/routers/web/repo"
"code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/convert"
@ -77,6 +78,7 @@ func List(ctx *context.Context) {
// Get all runner labels // Get all runner labels
runners, err := db.Find[actions_model.ActionRunner](ctx, actions_model.FindRunnerOptions{ runners, err := db.Find[actions_model.ActionRunner](ctx, actions_model.FindRunnerOptions{
RepoID: ctx.Repo.Repository.ID, RepoID: ctx.Repo.Repository.ID,
IsOnline: util.OptionalBoolTrue,
WithAvailable: true, WithAvailable: true,
}) })
if err != nil { if err != nil {
@ -113,7 +115,7 @@ func List(ctx *context.Context) {
continue continue
} }
if !allRunnerLabels.Contains(ro) { if !allRunnerLabels.Contains(ro) {
workflow.ErrMsg = ctx.Locale.Tr("actions.runs.no_matching_runner_helper", ro) workflow.ErrMsg = ctx.Locale.Tr("actions.runs.no_matching_online_runner_helper", ro)
break break
} }
} }

View File

@ -315,8 +315,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
lexerName = lexerNameForLine lexerName = lexerNameForLine
} }
br.EscapeStatus, line = charset.EscapeControlHTML(line, ctx.Locale) br.EscapeStatus, br.Code = charset.EscapeControlHTML(line, ctx.Locale)
br.Code = gotemplate.HTML(line)
rows = append(rows, br) rows = append(rows, br)
escapeStatus = escapeStatus.Or(br.EscapeStatus) escapeStatus = escapeStatus.Or(br.EscapeStatus)
} }

View File

@ -158,7 +158,7 @@ func RestoreBranchPost(ctx *context.Context) {
if err := repo_service.PushUpdate( if err := repo_service.PushUpdate(
&repo_module.PushUpdateOptions{ &repo_module.PushUpdateOptions{
RefFullName: git.RefNameFromBranch(deletedBranch.Name), RefFullName: git.RefNameFromBranch(deletedBranch.Name),
OldCommitID: objectFormat.Empty().String(), OldCommitID: objectFormat.EmptyObjectID().String(),
NewCommitID: deletedBranch.CommitID, NewCommitID: deletedBranch.CommitID,
PusherID: ctx.Doer.ID, PusherID: ctx.Doer.ID,
PusherName: ctx.Doer.Name, PusherName: ctx.Doer.Name,

View File

@ -317,7 +317,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
ci.BaseBranch = baseCommit.ID.String() ci.BaseBranch = baseCommit.ID.String()
ctx.Data["BaseBranch"] = ci.BaseBranch ctx.Data["BaseBranch"] = ci.BaseBranch
baseIsCommit = true baseIsCommit = true
} else if ci.BaseBranch == objectFormat.Empty().String() { } else if ci.BaseBranch == objectFormat.EmptyObjectID().String() {
if isSameRepo { if isSameRepo {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch)) ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch))
} else { } else {

View File

@ -329,7 +329,7 @@ func dummyInfoRefs(ctx *context.Context) {
} }
}() }()
if err := git.InitRepository(ctx, tmpDir, true, git.ObjectFormatFromID(git.Sha1)); err != nil { if err := git.InitRepository(ctx, tmpDir, true, git.Sha1ObjectFormat.Name()); err != nil {
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err) log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)
return return
} }

View File

@ -289,7 +289,7 @@ func CreatePost(ctx *context.Context) {
AutoInit: form.AutoInit, AutoInit: form.AutoInit,
IsTemplate: form.Template, IsTemplate: form.Template,
TrustModel: repo_model.ToTrustModel(form.TrustModel), TrustModel: repo_model.ToTrustModel(form.TrustModel),
ObjectFormat: form.ObjectFormat, ObjectFormatName: form.ObjectFormatName,
}) })
if err == nil { if err == nil {
log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name) log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)

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