diff --git a/MAINTAINERS b/MAINTAINERS index 0c94df87b9530..f43ba5ab99065 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -43,3 +43,4 @@ Kyle Dumont (@kdumontnu) Patrick Schratz (@pat-s) Janis Estelmann (@KN4CK3R) Steven Kriegler (@justusbunsi) +Jimmy Praet (@jpraet) diff --git a/cmd/convert.go b/cmd/convert.go index 23a3d8dbe9d51..e2ffd403acbc3 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -27,10 +27,10 @@ func runConvert(ctx *cli.Context) error { return err } - log.Trace("AppPath: %s", setting.AppPath) - log.Trace("AppWorkPath: %s", setting.AppWorkPath) - log.Trace("Custom path: %s", setting.CustomPath) - log.Trace("Log path: %s", setting.LogRootPath) + log.Info("AppPath: %s", setting.AppPath) + log.Info("AppWorkPath: %s", setting.AppWorkPath) + log.Info("Custom path: %s", setting.CustomPath) + log.Info("Log path: %s", setting.LogRootPath) setting.InitDBConfig() if !setting.Database.UseMySQL { diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go index cea640b53438d..69813e3c872f6 100644 --- a/cmd/dump_repo.go +++ b/cmd/dump_repo.go @@ -69,7 +69,7 @@ var CmdDumpRepository = cli.Command{ cli.StringFlag{ Name: "units", Value: "", - Usage: `Which items will be migrated, one or more units should be separated as comma. + Usage: `Which items will be migrated, one or more units should be separated as comma. wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, }, }, @@ -80,10 +80,10 @@ func runDumpRepository(ctx *cli.Context) error { return err } - log.Trace("AppPath: %s", setting.AppPath) - log.Trace("AppWorkPath: %s", setting.AppWorkPath) - log.Trace("Custom path: %s", setting.CustomPath) - log.Trace("Log path: %s", setting.LogRootPath) + log.Info("AppPath: %s", setting.AppPath) + log.Info("AppWorkPath: %s", setting.AppWorkPath) + log.Info("Custom path: %s", setting.CustomPath) + log.Info("Log path: %s", setting.LogRootPath) setting.InitDBConfig() var ( diff --git a/cmd/migrate.go b/cmd/migrate.go index 2428925887c9a..23bc97b0c41f2 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -28,10 +28,10 @@ func runMigrate(ctx *cli.Context) error { return err } - log.Trace("AppPath: %s", setting.AppPath) - log.Trace("AppWorkPath: %s", setting.AppWorkPath) - log.Trace("Custom path: %s", setting.CustomPath) - log.Trace("Log path: %s", setting.LogRootPath) + log.Info("AppPath: %s", setting.AppPath) + log.Info("AppWorkPath: %s", setting.AppWorkPath) + log.Info("Custom path: %s", setting.CustomPath) + log.Info("Log path: %s", setting.LogRootPath) setting.InitDBConfig() if err := models.NewEngine(context.Background(), migrations.Migrate); err != nil { diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 871baed92de9e..8ff84d690b9ab 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -110,10 +110,10 @@ func runMigrateStorage(ctx *cli.Context) error { return err } - log.Trace("AppPath: %s", setting.AppPath) - log.Trace("AppWorkPath: %s", setting.AppWorkPath) - log.Trace("Custom path: %s", setting.CustomPath) - log.Trace("Log path: %s", setting.LogRootPath) + log.Info("AppPath: %s", setting.AppPath) + log.Info("AppWorkPath: %s", setting.AppWorkPath) + log.Info("Custom path: %s", setting.CustomPath) + log.Info("Log path: %s", setting.LogRootPath) setting.InitDBConfig() if err := models.NewEngine(context.Background(), migrations.Migrate); err != nil { diff --git a/cmd/serv.go b/cmd/serv.go index 1c9f5dc44e9d3..40f8b89c9a98b 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -6,14 +6,17 @@ package cmd import ( + "context" "fmt" "net/http" "net/url" "os" "os/exec" + "os/signal" "regexp" "strconv" "strings" + "syscall" "time" "code.gitea.io/gitea/models" @@ -273,12 +276,31 @@ func runServ(c *cli.Context) error { verb = strings.Replace(verb, "-", " ", 1) } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go func() { + // install notify + signalChannel := make(chan os.Signal, 1) + + signal.Notify( + signalChannel, + syscall.SIGINT, + syscall.SIGTERM, + ) + select { + case <-signalChannel: + case <-ctx.Done(): + } + cancel() + signal.Reset() + }() + var gitcmd *exec.Cmd verbs := strings.Split(verb, " ") if len(verbs) == 2 { - gitcmd = exec.Command(verbs[0], verbs[1], repoPath) + gitcmd = exec.CommandContext(ctx, verbs[0], verbs[1], repoPath) } else { - gitcmd = exec.Command(verb, repoPath) + gitcmd = exec.CommandContext(ctx, verb, repoPath) } gitcmd.Dir = setting.RepoRootPath diff --git a/cmd/web.go b/cmd/web.go index 0ba14ae70642c..6953e7c64f5d9 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -47,6 +47,14 @@ and it takes care of all the other things for you`, Value: setting.PIDFile, Usage: "Custom pid file path", }, + cli.BoolFlag{ + Name: "quiet, q", + Usage: "Only display Fatal logging errors until logging is set-up", + }, + cli.BoolFlag{ + Name: "verbose", + Usage: "Set initial logging to TRACE level until logging is properly set-up", + }, }, } @@ -71,6 +79,14 @@ func runHTTPRedirector() { } func runWeb(ctx *cli.Context) error { + if ctx.Bool("verbose") { + _ = log.DelLogger("console") + log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "trace", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout)) + } else if ctx.Bool("quiet") { + _ = log.DelLogger("console") + log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "fatal", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout)) + } + managerCtx, cancel := context.WithCancel(context.Background()) graceful.InitManager(managerCtx) defer cancel() diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 9ce84f762cecd..902c9ea623473 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -26,6 +26,7 @@ import ( "time" "code.gitea.io/gitea/models" + gitea_git "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/external" "code.gitea.io/gitea/modules/setting" @@ -79,7 +80,7 @@ func runPR() { setting.RunUser = curUser.Username log.Printf("[PR] Loading fixtures data ...\n") - setting.CheckLFSVersion() + gitea_git.CheckLFSVersion() //models.LoadConfigs() /* setting.Database.Type = "sqlite3" diff --git a/contrib/update_dependencies.sh b/contrib/update_dependencies.sh new file mode 100644 index 0000000000000..f6f26c66cb023 --- /dev/null +++ b/contrib/update_dependencies.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +grep 'git' go.mod | grep '\.com' | grep -v indirect | grep -v replace | cut -f 2 | cut -d ' ' -f 1 | while read line; do + go get -u "$line" + make vendor + git add . + git commit -S -m "update $line" +done diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index d7e1f05ba1bcc..6e8df09ca4d54 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -573,6 +573,9 @@ PATH = ;; ;; Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled) ;PULL_REQUEST_PUSH_MESSAGE = true +;; +;; (Go-Git only) Don't cache objects greater than this in memory. (Set to 0 to disable.) +;LARGE_OBJECT_THRESHOLD = 1048576 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -654,9 +657,18 @@ PATH = ;DEFAULT_USER_IS_RESTRICTED = false ;; ;; Either "public", "limited" or "private", default is "public" -;; Limited is for signed user only -;; Private is only for member of the organization -;; Public is for everyone +;; Limited is for users visible only to signed users +;; Private is for users visible only to members of their organizations +;; Public is for users visible for everyone +;DEFAULT_USER_VISIBILITY = public +;; +;; Set whitch visibibilty modes a user can have +;ALLOWED_USER_VISIBILITY_MODES = public,limited,private +;; +;; Either "public", "limited" or "private", default is "public" +;; Limited is for organizations visible only to signed users +;; Private is for organizations visible only to members of the organization +;; Public is for organizations visible to everyone ;DEFAULT_ORG_VISIBILITY = public ;; ;; Default value for DefaultOrgMemberVisible @@ -708,6 +720,8 @@ PATH = ;; ;; Minimum amount of time a user must exist before comments are kept when the user is deleted. ;USER_DELETE_WITH_COMMENTS_MAX_TIME = 0 +;; Valid site url schemes for user profiles +;VALID_SITE_URL_SCHEMES=http,https ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1021,11 +1035,16 @@ PATH = ;; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`. ;THEMES = gitea,arc-green ;; -;;All available reactions users can choose on issues/prs and comments. -;;Values can be emoji alias (:smile:) or a unicode emoji. -;;For custom reactions, add a tightly cropped square image to public/emoji/img/reaction_name.png +;; All available reactions users can choose on issues/prs and comments. +;; Values can be emoji alias (:smile:) or a unicode emoji. +;; For custom reactions, add a tightly cropped square image to public/img/emoji/reaction_name.png ;REACTIONS = +1, -1, laugh, hooray, confused, heart, rocket, eyes ;; +;; Additional Emojis not defined in the utf8 standard +;; By default we support gitea (:gitea:), to add more copy them to public/img/emoji/emoji_name.png and add it to this config. +;; Dont mistake it for Reactions. +;CUSTOM_EMOJIS = gitea, codeberg, gitlab, git, github, gogs +;; ;; Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used. ;DEFAULT_SHOW_FULL_NAME = false ;; diff --git a/docs/config.yaml b/docs/config.yaml index c2d9dc5e521cf..9b446f35b6ab8 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -18,7 +18,7 @@ params: description: Git with a cup of tea author: The Gitea Authors website: https://docs.gitea.io - version: 1.14.2 + version: 1.14.3 minGoVersion: 1.14 goVersion: 1.16 minNodeVersion: 12.17 diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index d45d899d263a9..30914e63398dd 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -180,7 +180,10 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB) - `REACTIONS`: All available reactions users can choose on issues/prs and comments Values can be emoji alias (:smile:) or a unicode emoji. - For custom reactions, add a tightly cropped square image to public/emoji/img/reaction_name.png + For custom reactions, add a tightly cropped square image to public/img/emoji/reaction_name.png +- `CUSTOM_EMOJIS`: **gitea, codeberg, gitlab, git, github, gogs**: Additional Emojis not defined in the utf8 standard. + By default we support gitea (:gitea:), to add more copy them to public/img/emoji/emoji_name.png and + add it to this config. - `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used. - `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page. - `USE_SERVICE_WORKER`: **true**: Whether to enable a Service Worker to cache frontend assets. @@ -389,7 +392,7 @@ relation to port exhaustion. - `MAX_ATTEMPTS`: **10**: Maximum number of attempts to create the wrapped queue - `TIMEOUT`: **GRACEFUL_HAMMER_TIME + 30s**: Timeout the creation of the wrapped queue if it takes longer than this to create. - Queues by default come with a dynamically scaling worker pool. The following settings configure this: -- `WORKERS`: **0** (v1.14 and before: **1**): Number of initial workers for the queue. +- `WORKERS`: **0** (v1.14 and before: **1**): Number of initial workers for the queue. - `MAX_WORKERS`: **10**: Maximum number of worker go-routines for the queue. - `BLOCK_TIMEOUT`: **1s**: If the queue blocks for this time, boost the number of workers - the `BLOCK_TIMEOUT` will then be doubled before boosting again whilst the boost is ongoing. - `BOOST_TIMEOUT`: **5m**: Boost workers will timeout after this long. @@ -513,6 +516,8 @@ relation to port exhaustion. - `SHOW_MILESTONES_DASHBOARD_PAGE`: **true** Enable this to show the milestones dashboard page - a view of all the user's milestones - `AUTO_WATCH_NEW_REPOS`: **true**: Enable this to let all organisation users watch new repos when they are created - `AUTO_WATCH_ON_CHANGES`: **false**: Enable this to make users watch a repository after their first commit to it +- `DEFAULT_USER_VISIBILITY`: **public**: Set default visibility mode for users, either "public", "limited" or "private". +- `ALLOWED_USER_VISIBILITY_MODES`: **public,limited,private**: Set whitch visibibilty modes a user can have - `DEFAULT_ORG_VISIBILITY`: **public**: Set default visibility mode for organisations, either "public", "limited" or "private". - `DEFAULT_ORG_MEMBER_VISIBLE`: **false** True will make the membership of the users visible when added to the organisation. - `ALLOW_ONLY_INTERNAL_REGISTRATION`: **false** Set to true to force registration only via gitea. @@ -520,6 +525,7 @@ relation to port exhaustion. - `NO_REPLY_ADDRESS`: **noreply.DOMAIN** Value for the domain part of the user's email address in the git log if user has set KeepEmailPrivate to true. DOMAIN resolves to the value in server.DOMAIN. The user's email will be replaced with a concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS. - `USER_DELETE_WITH_COMMENTS_MAX_TIME`: **0** Minimum amount of time a user must exist before comments are kept when the user is deleted. +- `VALID_SITE_URL_SCHEMES`: **http, https**: Valid site url schemes for user profiles ### Service - Expore (`service.explore`) @@ -832,7 +838,7 @@ NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take ef - `PULL_REQUEST_PUSH_MESSAGE`: **true**: Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled) - `VERBOSE_PUSH`: **true**: Print status information about pushes as they are being processed. - `VERBOSE_PUSH_DELAY`: **5s**: Only print verbose information if push takes longer than this delay. - +- `LARGE_OBJECT_THRESHOLD`: **1048576**: (Go-Git only), don't cache objects greater than this in memory. (Set to 0 to disable.) ## Git - Timeout settings (`git.timeout`) - `DEFAUlT`: **360**: Git operations default timeout seconds. - `MIGRATE`: **600**: Migrate external repositories timeout seconds. diff --git a/docs/content/doc/advanced/customizing-gitea.en-us.md b/docs/content/doc/advanced/customizing-gitea.en-us.md index 7a8e01d356072..6a5f495805cbc 100644 --- a/docs/content/doc/advanced/customizing-gitea.en-us.md +++ b/docs/content/doc/advanced/customizing-gitea.en-us.md @@ -56,7 +56,7 @@ To make Gitea serve custom public files (like pages and images), use the folder `$GITEA_CUSTOM/public/` as the webroot. Symbolic links will be followed. For example, a file `image.png` stored in `$GITEA_CUSTOM/public/`, can be accessed with -the url `http://gitea.domain.tld/image.png`. +the url `http://gitea.domain.tld/assets/image.png`. ## Changing the logo diff --git a/docs/content/doc/advanced/customizing-gitea.zh-cn.md b/docs/content/doc/advanced/customizing-gitea.zh-cn.md index 91762b13d96b9..4640f878ad0bd 100644 --- a/docs/content/doc/advanced/customizing-gitea.zh-cn.md +++ b/docs/content/doc/advanced/customizing-gitea.zh-cn.md @@ -40,7 +40,7 @@ Gitea 引用 `custom` 目录中的自定义配置文件来覆盖配置、模板 将自定义的公共文件(比如页面和图片)作为 webroot 放在 `custom/public/` 中来让 Gitea 提供这些自定义内容(符号链接将被追踪)。 -举例说明:`image.png` 存放在 `custom/public/`中,那么它可以通过链接 http://gitea.domain.tld/image.png 访问。 +举例说明:`image.png` 存放在 `custom/public/`中,那么它可以通过链接 http://gitea.domain.tld/assets/image.png 访问。 ## 修改默认头像 diff --git a/docs/content/doc/developers/integrations.en-us.md b/docs/content/doc/developers/integrations.en-us.md index a1d8f0f938ce0..8a111a3a8dc68 100644 --- a/docs/content/doc/developers/integrations.en-us.md +++ b/docs/content/doc/developers/integrations.en-us.md @@ -20,7 +20,7 @@ projects. We are curating a list over at [awesome-gitea](https://gitea.com/gitea/awesome-gitea) to track these! -If you are looking for [CI/CD](https://gitea.com/gitea/awesome-gitea#devops), -an [SDK](https://gitea.com/gitea/awesome-gitea#sdk), -or even some extra [themes](https://gitea.com/gitea/awesome-gitea#themes), +If you are looking for [CI/CD](https://gitea.com/gitea/awesome-gitea#user-content-devops), +an [SDK](https://gitea.com/gitea/awesome-gitea#user-content-sdk), +or even some extra [themes](https://gitea.com/gitea/awesome-gitea#user-content-themes), you can find them listed in the [awesome-gitea](https://gitea.com/gitea/awesome-gitea) repository! diff --git a/docs/content/doc/developers/integrations.zh-tw.md b/docs/content/doc/developers/integrations.zh-tw.md index 6a3f3f8bf326a..6991ec4ae8860 100644 --- a/docs/content/doc/developers/integrations.zh-tw.md +++ b/docs/content/doc/developers/integrations.zh-tw.md @@ -19,4 +19,4 @@ Gitea 有著很棒的第三方整合社群, 以及其它有著一流支援的 我們持續的整理一份清單以追蹤他們!請到 [awesome-gitea](https://gitea.com/gitea/awesome-gitea) 查看。 -如果您正在找尋有關 [CI/CD](https://gitea.com/gitea/awesome-gitea#devops)、[SDK](https://gitea.com/gitea/awesome-gitea#sdk) 或是其它佈景主題,您可以在存儲庫 [awesome-gitea](https://gitea.com/gitea/awesome-gitea) 找到他們。 +如果您正在找尋有關 [CI/CD](https://gitea.com/gitea/awesome-gitea#user-content-devops)、[SDK](https://gitea.com/gitea/awesome-gitea#user-content-sdk) 或是其它佈景主題,您可以在存儲庫 [awesome-gitea](https://gitea.com/gitea/awesome-gitea) 找到他們。 diff --git a/docs/content/doc/installation/from-binary.en-us.md b/docs/content/doc/installation/from-binary.en-us.md index 9d8864956b28e..aa075bb239e1b 100644 --- a/docs/content/doc/installation/from-binary.en-us.md +++ b/docs/content/doc/installation/from-binary.en-us.md @@ -32,13 +32,17 @@ chmod +x gitea ``` ## Verify GPG signature -Gitea signs all binaries with a [GPG key](https://keys.openpgp.org/search?q=teabot%40gitea.io) to prevent against unwanted modification of binaries. To validate the binary, download the signature file which ends in `.asc` for the binary you downloaded and use the gpg command line tool. +Gitea signs all binaries with a [GPG key](https://keys.openpgp.org/search?q=teabot%40gitea.io) to prevent against unwanted modification of binaries. +To validate the binary, download the signature file which ends in `.asc` for the binary you downloaded and use the gpg command line tool. ```sh gpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2 gpg --verify gitea-{{< version >}}-linux-amd64.asc gitea-{{< version >}}-linux-amd64 ``` +Look for the text `Good signature from "Teabot "` to assert a good binary, +despite warnings like `This key is not certified with a trusted signature!`. + ## Recommended server configuration **NOTE:** Many of the following directories can be configured using [Environment Variables]({{< relref "doc/advanced/environment-variables.en-us.md" >}}) as well! diff --git a/docs/content/doc/installation/from-package.en-us.md b/docs/content/doc/installation/from-package.en-us.md index cdb5833e33ca3..bc349ba42ef9e 100644 --- a/docs/content/doc/installation/from-package.en-us.md +++ b/docs/content/doc/installation/from-package.en-us.md @@ -2,7 +2,7 @@ date: "2016-12-01T16:00:00+02:00" title: "Installation from package" slug: "install-from-package" -weight: 10 +weight: 20 toc: false draft: false menu: @@ -92,18 +92,6 @@ is in `/usr/local/etc/rc.d/gitea`. To enable Gitea to run as a service, run `sysrc gitea_enable=YES` and start it with `service gitea start`. -## Cloudron - -Gitea is available as a 1-click install on [Cloudron](https://cloudron.io). -Cloudron makes it easy to run apps like Gitea on your server and keep them up-to-date and secure. - -[![Install](/cloudron.svg)](https://cloudron.io/button.html?app=io.gitea.cloudronapp) - -The Gitea package is maintained [here](https://git.cloudron.io/cloudron/gitea-app). - -There is a [demo instance](https://my.demo.cloudron.io) (username: cloudron password: cloudron) where -you can experiment with running Gitea. - ## Third-party Various other third-party packages of Gitea exist. diff --git a/docs/content/doc/installation/on-cloud-provider.md b/docs/content/doc/installation/on-cloud-provider.md new file mode 100644 index 0000000000000..c61c042af2424 --- /dev/null +++ b/docs/content/doc/installation/on-cloud-provider.md @@ -0,0 +1,44 @@ +--- +date: "2016-12-01T16:00:00+02:00" +title: "Install on Cloud Provider" +slug: "install-on-cloud-provider" +weight: 20 +toc: false +draft: false +menu: + sidebar: + parent: "installation" + name: "On cloud provider" + weight: 20 + identifier: "install-on-cloud-provider" +--- + +# Installation on Cloud Provider + +**Table of Contents** + +{{< toc >}} + +## Cloudron + +Gitea is available as a 1-click install on [Cloudron](https://cloudron.io). +Cloudron makes it easy to run apps like Gitea on your server and keep them up-to-date and secure. + +[![Install](/cloudron.svg)](https://cloudron.io/button.html?app=io.gitea.cloudronapp) + +The Gitea package is maintained [here](https://git.cloudron.io/cloudron/gitea-app). + +There is a [demo instance](https://my.demo.cloudron.io) (username: cloudron password: cloudron) where +you can experiment with running Gitea. + +## Vultr + +Gitea can found in [Vultr](https://www.vultr.com)'s marketplace. + +To deploy it have a look at https://www.vultr.com/marketplace/apps/gitea. + +## DigitalOcean + +[DigitalOcean](https://www.digitalocean.com) has gitea as droplet in his marketplace. + +Just create a new [Gitea Droplet](https://marketplace.digitalocean.com/apps/gitea). diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index 40933a7b333c5..0bc8d70fdb53a 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -46,6 +46,8 @@ Starts the server: - `--port number`, `-p number`: Port number. Optional. (default: 3000). Overrides configuration file. - `--install-port number`: Port number to run the install page on. Optional. (default: 3000). Overrides configuration file. - `--pid path`, `-P path`: Pidfile path. Optional. + - `--quiet`, `-q`: Only emit Fatal logs on the console for logs emitted before logging set up. + - `--verbose`: Emit tracing logs on the console for logs emitted before logging is set-up. - Examples: - `gitea web` - `gitea web --port 80` diff --git a/docs/content/doc/usage/fail2ban-setup.en-us.md b/docs/content/doc/usage/fail2ban-setup.en-us.md index 790d4c020b652..f96cf889a3984 100644 --- a/docs/content/doc/usage/fail2ban-setup.en-us.md +++ b/docs/content/doc/usage/fail2ban-setup.en-us.md @@ -29,22 +29,32 @@ on a bad authentication from the web or CLI using SSH or HTTP respectively: ```log 2020/10/15 16:05:09 modules/ssh/ssh.go:143:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx ``` +(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.) ```log 2020/10/15 16:05:09 modules/ssh/ssh.go:155:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx ``` +(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.) ```log 2020/10/15 16:05:09 modules/ssh/ssh.go:198:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx ``` +(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.) ```log 2020/10/15 16:05:09 modules/ssh/ssh.go:213:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx ``` +(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.) ```log 2020/10/15 16:05:09 modules/ssh/ssh.go:227:publicKeyHandler() [W] Failed authentication attempt from xxx.xxx.xxx.xxx ``` +(DEPRECATED: This may be a false positive as the user may still go on to correctly authenticate.) + +```log +2020/10/15 16:05:09 modules/ssh/ssh.go:249:sshConnectionFailed() [W] Failed authentication attempt from xxx.xxx.xxx.xxx +``` +(From 1.15 this new message will available and doesn't have any of the false positive results that above messages from publicKeyHandler do. This will only be logged if the user has completely failed authentication.) ```log 2020/10/15 16:08:44 ...s/context/context.go:204:HandleText() [E] invalid credentials from xxx.xxx.xxx.xxx diff --git a/go.mod b/go.mod index 0ac321f0e012c..82c98c9167874 100644 --- a/go.mod +++ b/go.mod @@ -14,16 +14,15 @@ require ( github.com/Microsoft/go-winio v0.5.0 // indirect github.com/NYTimes/gziphandler v1.1.1 github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c // indirect - github.com/PuerkitoBio/goquery v1.6.1 - github.com/RoaringBitmap/roaring v0.7.3 // indirect - github.com/alecthomas/chroma v0.9.1 + github.com/PuerkitoBio/goquery v1.7.0 + github.com/RoaringBitmap/roaring v0.8.0 // indirect + github.com/alecthomas/chroma v0.9.2 github.com/andybalholm/brotli v1.0.3 // indirect github.com/andybalholm/cascadia v1.2.0 // indirect - github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect - github.com/blevesearch/bleve/v2 v2.0.5 + github.com/blevesearch/bleve/v2 v2.0.6 github.com/boombuler/barcode v1.0.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect - github.com/caddyserver/certmagic v0.13.1 + github.com/caddyserver/certmagic v0.14.0 github.com/chi-middleware/proxy v1.1.1 github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect github.com/couchbase/gomemcached v0.1.2 // indirect @@ -36,15 +35,15 @@ require ( github.com/editorconfig/editorconfig-core-go/v2 v2.4.2 github.com/emirpasic/gods v1.12.0 github.com/ethantkoenig/rupture v1.0.0 - github.com/gliderlabs/ssh v0.3.2 + github.com/gliderlabs/ssh v0.3.3 github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect github.com/go-chi/chi v1.5.4 github.com/go-chi/cors v1.2.0 - github.com/go-enry/go-enry/v2 v2.7.0 + github.com/go-enry/go-enry/v2 v2.7.1 github.com/go-git/go-billy/v5 v5.3.1 - github.com/go-git/go-git/v5 v5.4.2 + github.com/go-git/go-git/v5 v5.4.3-0.20210630082519-b4368b2a2ca4 github.com/go-ldap/ldap/v3 v3.3.0 - github.com/go-redis/redis/v8 v8.10.0 + github.com/go-redis/redis/v8 v8.11.0 github.com/go-sql-driver/mysql v1.6.0 github.com/go-swagger/go-swagger v0.27.0 github.com/go-testfixtures/testfixtures/v3 v3.6.1 @@ -52,6 +51,7 @@ require ( github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 + github.com/golang/snappy v0.0.4 // indirect github.com/google/go-github/v32 v32.1.0 github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.2.0 @@ -61,7 +61,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.0 // indirect github.com/hashicorp/go-version v1.3.1 - github.com/hashicorp/golang-lru v0.5.1 + github.com/hashicorp/golang-lru v0.5.4 github.com/huandu/xstrings v1.3.2 github.com/issue9/identicon v1.2.0 github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 @@ -69,21 +69,21 @@ require ( github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kevinburke/ssh_config v1.1.0 // indirect github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 - github.com/klauspost/compress v1.13.0 + github.com/klauspost/compress v1.13.1 + github.com/klauspost/cpuid/v2 v2.0.7 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/lafriks/xormstore v1.4.0 github.com/lib/pq v1.10.2 - github.com/libdns/libdns v0.2.1 // indirect github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 github.com/markbates/goth v1.67.1 github.com/mattn/go-isatty v0.0.13 github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mattn/go-sqlite3 v1.14.7 github.com/mholt/archiver/v3 v3.5.0 - github.com/microcosm-cc/bluemonday v1.0.9 - github.com/miekg/dns v1.1.42 // indirect + github.com/microcosm-cc/bluemonday v1.0.14 + github.com/miekg/dns v1.1.43 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/minio-go/v7 v7.0.10 + github.com/minio/minio-go/v7 v7.0.12 github.com/minio/sha256-simd v1.0.0 // indirect github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect github.com/msteinert/pam v0.0.0-20201130170657-e61372126161 @@ -91,9 +91,9 @@ require ( github.com/niklasfasching/go-org v1.5.0 github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/oliamb/cutter v0.2.2 - github.com/olivere/elastic/v7 v7.0.24 + github.com/olivere/elastic/v7 v7.0.25 github.com/pelletier/go-toml v1.9.0 // indirect - github.com/pierrec/lz4/v4 v4.1.7 // indirect + github.com/pierrec/lz4/v4 v4.1.8 // indirect github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.3.0 github.com/prometheus/client_golang v1.11.0 @@ -113,23 +113,25 @@ require ( github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae github.com/unrolled/render v1.4.0 github.com/urfave/cli v1.22.5 - github.com/xanzy/go-gitlab v0.50.0 + github.com/xanzy/go-gitlab v0.50.1 github.com/yohcop/openid-go v1.0.0 - github.com/yuin/goldmark v1.3.7 + github.com/yuin/goldmark v1.3.9 github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 github.com/yuin/goldmark-meta v1.0.0 go.etcd.io/bbolt v1.3.6 // indirect go.jolheiser.com/hcaptcha v0.0.4 go.jolheiser.com/pwn v0.0.3 + go.uber.org/atomic v1.8.0 // indirect go.uber.org/multierr v1.7.0 // indirect - go.uber.org/zap v1.17.0 // indirect - golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a - golang.org/x/net v0.0.0-20210525063256-abc453219eb5 - golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c - golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 + go.uber.org/zap v1.18.1 // indirect + golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e + golang.org/x/net v0.0.0-20210614182718-04defd469f4e + golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c golang.org/x/text v0.3.6 - golang.org/x/time v0.0.0-20210608053304-ed9ce3a009e4 // indirect + golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect golang.org/x/tools v0.1.0 + google.golang.org/protobuf v1.27.1 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.62.0 @@ -137,7 +139,7 @@ require ( mvdan.cc/xurls/v2 v2.2.0 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 xorm.io/builder v0.3.9 - xorm.io/xorm v1.1.0 + xorm.io/xorm v1.1.1 ) replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 diff --git a/go.sum b/go.sum index 31c66d0c4a0f3..9c4f97329a03b 100644 --- a/go.sum +++ b/go.sum @@ -71,17 +71,17 @@ github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/ github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c h1:bNpaLLv2Y4kslsdkdCwAYu8Bak1aGVtxwi8Z/wy4Yuo= github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= -github.com/PuerkitoBio/goquery v1.6.1 h1:FgjbQZKl5HTmcn4sKBgvx8vv63nhyhIpv7lJpFGCWpk= -github.com/PuerkitoBio/goquery v1.6.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= +github.com/PuerkitoBio/goquery v1.7.0 h1:O5SP3b9JWqMSVMG69zMfj577zwkSNpxrFf7ybS74eiw= +github.com/PuerkitoBio/goquery v1.7.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= -github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= -github.com/RoaringBitmap/roaring v0.7.3 h1:RwirWpvFONt2EwHHEHhER7S4BHZkyj3qL5LXLlnQPZ4= github.com/RoaringBitmap/roaring v0.7.3/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= +github.com/RoaringBitmap/roaring v0.8.0 h1:3naGkGvYAANr3ntyV+OpyhH+/rDaE2om9coNpIIdWAA= +github.com/RoaringBitmap/roaring v0.8.0/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= @@ -89,8 +89,8 @@ github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= github.com/alecthomas/chroma v0.7.2-0.20200305040604-4f3623dce67a/go.mod h1:fv5SzZPFJbwp2NXJWpFIX7DZS4HgV1K4ew4Pc2OZD9s= github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= -github.com/alecthomas/chroma v0.9.1 h1:cBmvQqRImzR5aWqdMxYZByND4S7BCS/g0svZb28h0Dc= -github.com/alecthomas/chroma v0.9.1/go.mod h1:eMuEnpA18XbG/WhOWtCzJHS7WqEtDAI+HxdwoW0nVSk= +github.com/alecthomas/chroma v0.9.2 h1:yU1sE2+TZbLIQPMk30SolL2Hn53SR/Pv750f7qZ/XMs= +github.com/alecthomas/chroma v0.9.2/go.mod h1:eMuEnpA18XbG/WhOWtCzJHS7WqEtDAI+HxdwoW0nVSk= github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= @@ -126,22 +126,23 @@ github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:W github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= -github.com/aws/aws-sdk-go v1.38.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.17/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.1.10/go.mod h1:w0XsmFg8qg6cmpTtJ0z3pKgjTDBMMnI/+I2syrE6XBE= github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blevesearch/bleve/v2 v2.0.1/go.mod h1:OBP2Pktqik8vEiUlGhuWjYx7KiO4zD542+DHqICwM5w= -github.com/blevesearch/bleve/v2 v2.0.5 h1:184yM7uei4Cmw2SdKSdMWYg46OFRKsr+s8hBYc2FbuU= -github.com/blevesearch/bleve/v2 v2.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM= +github.com/blevesearch/bleve/v2 v2.0.6 h1:2dV2S4pyUqQHftUFzM0htUCWC8MeRg2qsmgIvjnKlgU= +github.com/blevesearch/bleve/v2 v2.0.6/go.mod h1:UhqLjgDhN4mji6F1dL3fPghcqaBV6r6bXwKCdaBa3Is= github.com/blevesearch/bleve_index_api v1.0.0 h1:Ds3XeuTxjXCkG6pgIwWDRyooJKNIuOKemnN0N0IkhTU= github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= @@ -158,32 +159,31 @@ github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= github.com/blevesearch/upsidedown_store_api v1.0.1 h1:1SYRwyoFLwG3sj0ed89RLtM15amfX2pXlYbFOnF8zNU= github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJBf/a8h0FZY6xJbthIMm8myH2Q= -github.com/blevesearch/vellum v1.0.3/go.mod h1:2u5ax02KeDuNWu4/C+hVQMD6uLN4txH1JbtpaDNLJRo= -github.com/blevesearch/vellum v1.0.4 h1:o6t7NxTnThp1es52uQvOJJx+9yK/nKXlWC5xl4LCz1U= -github.com/blevesearch/vellum v1.0.4/go.mod h1:cMhywHI0de50f7Nj42YgvyD6bFJ2WkNRvNBlNMrEVgY= +github.com/blevesearch/vellum v1.0.5 h1:L5dJ7hKauRVbuH7I8uqLeSK92CPPY6FfrbAmLhAug8A= +github.com/blevesearch/vellum v1.0.5/go.mod h1:atE0EH3fvk43zzS7t1YNdNC7DbmcC3uz+eMD5xZ2OyQ= github.com/blevesearch/zapx/v11 v11.1.10/go.mod h1:DTjbcBqrr/Uo82UBilDC8lEew42gN/OcIyiTNFtSijc= -github.com/blevesearch/zapx/v11 v11.2.0 h1:GBkCJYsyj3eIU4+aiLPxoMz1PYvDbQZl/oXHIBZIP60= -github.com/blevesearch/zapx/v11 v11.2.0/go.mod h1:gN/a0alGw1FZt/YGTo1G6Z6XpDkeOfujX5exY9sCQQM= +github.com/blevesearch/zapx/v11 v11.2.1 h1:udluDHdr99gGSeL3vZLtJbML0OJ98mK1Peivtm5OYho= +github.com/blevesearch/zapx/v11 v11.2.1/go.mod h1:TBkJF5Qq0EwZbbBQmkW6/AQVSYwXXpp0xwtQ5wXHVMI= github.com/blevesearch/zapx/v12 v12.1.10/go.mod h1:14NmKnPrnKAIyiEJM566k/Jk+FQpuiflT5d3uaaK3MI= -github.com/blevesearch/zapx/v12 v12.2.0 h1:dyRcSoZVO1jktL4UpGkCEF1AYa3xhKPirh4/N+Va+Ww= -github.com/blevesearch/zapx/v12 v12.2.0/go.mod h1:fdjwvCwWWwJW/EYTYGtAp3gBA0geCYGLcVTtJEZnY6A= +github.com/blevesearch/zapx/v12 v12.2.1 h1:nbeecR8M3dEcIIYfKDaSRpJ9E205E7BvjhVwf/l5ajI= +github.com/blevesearch/zapx/v12 v12.2.1/go.mod h1:sSXvgEs7MKqqDIRSpyFd6ZJUEVlhxuDB0d8/WT2WlgA= github.com/blevesearch/zapx/v13 v13.1.10/go.mod h1:YsVY6YGpTEAlJOMjdL7EsdBLvjWd8kPa2gwJDNpqLJo= -github.com/blevesearch/zapx/v13 v13.2.0 h1:mUqbaqQABp8nBE4t4q2qMyHCCq4sykoV8r7aJk4ih3s= -github.com/blevesearch/zapx/v13 v13.2.0/go.mod h1:o5rAy/lRS5JpAbITdrOHBS/TugWYbkcYZTz6VfEinAQ= +github.com/blevesearch/zapx/v13 v13.2.1 h1:6K797fvkurY6heEMPhyUlq3VULIpkD1sbBqqQUMFf4g= +github.com/blevesearch/zapx/v13 v13.2.1/go.mod h1:Fblcy4ykPy7XiaZ2svvpQaYgEqI+8vkdvMVx5zcawF4= github.com/blevesearch/zapx/v14 v14.1.10/go.mod h1:hsULl5eJSxs5NEfBsmeT9qrqdCP+/ecpVZKt60M4V64= -github.com/blevesearch/zapx/v14 v14.2.0 h1:UsfRqvM9RJxKNKrkR1U7aYc1cv9MWx719fsAjbF6joI= -github.com/blevesearch/zapx/v14 v14.2.0/go.mod h1:GNgZusc1p4ot040cBQMRGEZobvwjCquiEKYh1xLFK9g= +github.com/blevesearch/zapx/v14 v14.2.1 h1:V3RzDc7XZ51Kv9ZhhzMlHCSoY4+jxqy9VBqHxTqW4pg= +github.com/blevesearch/zapx/v14 v14.2.1/go.mod h1:veKtVCDzl4vvYeT5zULXEXqPR948uilzixzmmdtpCkU= github.com/blevesearch/zapx/v15 v15.1.10/go.mod h1:4ypq25bwtSQKzwEF1UERyIhmGTbMT3brY/n4NC5gRnM= -github.com/blevesearch/zapx/v15 v15.2.0 h1:ZpibwcrrOaeslkOw3sJ7npP7KDgRHI/DkACjKTqFwyM= -github.com/blevesearch/zapx/v15 v15.2.0/go.mod h1:MmQceLpWfME4n1WrBFIwplhWmaQbQqLQARpaKUEOs/A= +github.com/blevesearch/zapx/v15 v15.2.1 h1:ZaqQiWLo0srtPvy3ozgpR9+Oabs3HQrF4uJM0HiKVBY= +github.com/blevesearch/zapx/v15 v15.2.1/go.mod h1:pUCN72ZJkVd7dU9lA4Fd8E3+fl5wv3JPpThk4FQ5bpA= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= -github.com/caddyserver/certmagic v0.13.1 h1:A5qLxh9J6/CYWEOHaj135IWAjCY0193ONxEy8jbOlPw= -github.com/caddyserver/certmagic v0.13.1/go.mod h1:+zhQtEgLOyXRA/KRduHXNhGGdTeqRM4ePj8eBGD/2CQ= +github.com/caddyserver/certmagic v0.14.0 h1:XW1o32s7smIYEJSc6g+N8YXljpjRo5ZE2zi3CIYTs74= +github.com/caddyserver/certmagic v0.14.0/go.mod h1:oRQOZmUVKwlpgNidslysHt05osM9uMrJ4YMk+Ot4P4Q= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -286,8 +286,8 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/gliderlabs/ssh v0.3.2 h1:gcfd1Aj/9RQxvygu4l3sak711f/5+VOwBw9C/7+N4EI= -github.com/gliderlabs/ssh v0.3.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.3.3 h1:mBQ8NiOgDkINJrZtoizkC3nDNYgSaWtxyem6S2XHBtA= +github.com/gliderlabs/ssh v0.3.3/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= @@ -302,8 +302,8 @@ github.com/go-chi/chi/v5 v5.0.1 h1:ALxjCrTf1aflOlkhMnCUP86MubbWFrzB3gkRPReLpTo= github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE= github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= -github.com/go-enry/go-enry/v2 v2.7.0 h1:bcAZfvX0LmAEMl8OEd8MPsfJCN2Io4mNU1an1Hh48VA= -github.com/go-enry/go-enry/v2 v2.7.0/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ= +github.com/go-enry/go-enry/v2 v2.7.1 h1:WCqtfyteIz61GYk9lRVy8HblvIv4cP9GIiwm/6txCbU= +github.com/go-enry/go-enry/v2 v2.7.1/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= @@ -313,8 +313,8 @@ github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Ai github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8= github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= -github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= -github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/go-git/go-git/v5 v5.4.3-0.20210630082519-b4368b2a2ca4 h1:1RSUwVK7VjTeA82kcLIqz1EU70QRwFdZUlJW58gP4GY= +github.com/go-git/go-git/v5 v5.4.3-0.20210630082519-b4368b2a2ca4/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -424,8 +424,8 @@ github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZ github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= -github.com/go-redis/redis/v8 v8.10.0 h1:OZwrQKuZqdJ4QIM8wn8rnuz868Li91xA3J2DEq+TPGA= -github.com/go-redis/redis/v8 v8.10.0/go.mod h1:vXLTvigok0VtUX0znvbcEW1SOt4OA9CU1ZfnOtKOaiM= +github.com/go-redis/redis/v8 v8.11.0 h1:O1Td0mQ8UFChQ3N9zFQqo6kTU2cJ+/it88gDB+zg0wo= +github.com/go-redis/redis/v8 v8.11.0/go.mod h1:DLomh7y2e3ggQXQLd1YgmvIfecPJoFl7WU5SOQ/r06M= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= @@ -508,8 +508,9 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -522,8 +523,9 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -598,8 +600,9 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -700,16 +703,17 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.0 h1:2T7tUoQrQT+fQWdaY5rjWztFGAFwbGD04iPJg90ZiOs= -github.com/klauspost/compress v1.13.0/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ= +github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.7 h1:U89pAFid7wpIWvTFJnMKgU+Sabb7DLEgHI7Xt8apo3Y= +github.com/klauspost/cpuid/v2 v2.0.7/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= @@ -737,7 +741,6 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:uNwtsDp7ci48vBTTxDuwcoTXz4lwtDTe7TjCQ0noaWY= @@ -790,17 +793,17 @@ github.com/mholt/acmez v0.1.3 h1:J7MmNIk4Qf9b8mAGqAh4XkNeowv3f1zW816yf4zt7Qk= github.com/mholt/acmez v0.1.3/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE= github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc= -github.com/microcosm-cc/bluemonday v1.0.9 h1:dpCwruVKoyrULicJwhuY76jB+nIxRVKv/e248Vx/BXg= -github.com/microcosm-cc/bluemonday v1.0.9/go.mod h1:B2riunDr9benLHghZB7hjIgdwSUzzs0pjCxFrWYEZFU= +github.com/microcosm-cc/bluemonday v1.0.14 h1:Djd+GeTanVeA23todvVC0AO5hsI+vAwQMLTy794Zr5I= +github.com/microcosm-cc/bluemonday v1.0.14/go.mod h1:beubO5lmWoy1tU8niaMyXNriNgROO37H3U/tsrcZsy0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY= github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.10 h1:1oUKe4EOPUEhw2qnPQaPsJ0lmVTYLFu03SiItauXs94= -github.com/minio/minio-go/v7 v7.0.10/go.mod h1:td4gW1ldOsj1PbSNS+WYK43j+P1XVhX/8W8awaYlBFo= +github.com/minio/minio-go/v7 v7.0.12 h1:/4pxUdwn9w0QEryNkrrWaodIESPRX+NxpO0Q6hVdaAA= +github.com/minio/minio-go/v7 v7.0.12/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= @@ -850,8 +853,8 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k= github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU= -github.com/olivere/elastic/v7 v7.0.24 h1:9ZcCQP3Pvgese7TaypYiVAL49sCEphyIwkVxtRf8jb8= -github.com/olivere/elastic/v7 v7.0.24/go.mod h1:OuWmD2DiuYhddWegBKPWQuelVKBLrW0fa/VUYgxuGTY= +github.com/olivere/elastic/v7 v7.0.25 h1:q3ef8PqC4PyT3b8BAcjDVo48KNzr0HVKosMqMsF+oME= +github.com/olivere/elastic/v7 v7.0.25/go.mod h1:ySKeM+7yrE9HmsUi6+vSp0anvWiDOuPa9kpuknxjKbU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -877,8 +880,8 @@ github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7 github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pierrec/lz4/v4 v4.1.7 h1:UDV9geJWhFIufAliH7HQlz9wP3JA0t748w+RwbWMLow= -github.com/pierrec/lz4/v4 v4.1.7/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.8 h1:ieHkV+i2BRzngO4Wd/3HGowuZStgq6QkPsD1eolNAO4= +github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -961,6 +964,8 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.1 h1:T/YLemO5Yp7KPzS+lVtu+WsHn8yoSwTfItdAd1r3cck= @@ -1037,8 +1042,8 @@ github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/xanzy/go-gitlab v0.50.0 h1:t7IoYTrnLSbdEZN7d8X/5zcr+ZM4TZQ2mXa8MqWlAZQ= -github.com/xanzy/go-gitlab v0.50.0/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE= +github.com/xanzy/go-gitlab v0.50.1 h1:eH1G0/ZV1j81rhGrtbcePjbM5Ern7mPA4Xjt+yE+2PQ= +github.com/xanzy/go-gitlab v0.50.1/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE= github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -1058,8 +1063,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.6/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.3.7 h1:NSaHgaeJFCtWXCBkBKXw0rhgMuJ0VoE9FB5mWldcrQ4= -github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.3.9 h1:XsVHmzm4P6g84IBbAj+WYMF/IEZ3J9+3I1wlqCNa/SQ= +github.com/yuin/goldmark v1.3.9/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 h1:0SJnXjE4jDClMW6grE0xpNhwpqbPwkBTn8zpVw5C0SI= github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01/go.mod h1:TwKQPa5XkCCRC2GRZ5wtfNUTQ2+9/i19mGRijFeJ4BE= github.com/yuin/goldmark-meta v1.0.0 h1:ScsatUIT2gFS6azqzLGUjgOnELsBOxMXerM3ogdJhAM= @@ -1091,19 +1096,14 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= -go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4= +go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -1113,8 +1113,9 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1136,12 +1137,12 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1164,6 +1165,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -1201,7 +1203,6 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1231,9 +1232,10 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210331060903-cb1fcc7394e5/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1245,8 +1247,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1290,7 +1292,6 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1332,13 +1333,15 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8= -golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1353,8 +1356,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210608053304-ed9ce3a009e4 h1:1asO3s7vR+9MvZSNRwUBBTjecxbGtfvmxjy2VWbFR5g= -golang.org/x/time v0.0.0-20210608053304-ed9ce3a009e4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 h1:Vv0JUPWTyeqUq42B2WJ1FeIDjjvGKoA2Ss+Ts0lAVbs= +golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1384,13 +1387,13 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1523,8 +1526,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= @@ -1611,5 +1615,5 @@ xorm.io/builder v0.3.8/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc= xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= xorm.io/xorm v1.0.6/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4= -xorm.io/xorm v1.1.0 h1:mkEsQXLauZajiOld2cB2PkFcUZKePepPgs1bC1dw8RA= -xorm.io/xorm v1.1.0/go.mod h1:EDzNHMuCVZNszkIRSLL2nI0zX+nQE8RstAVranlSfqI= +xorm.io/xorm v1.1.1 h1:cc1yot5rhoBucfk2lgZPZPEuI/9QsVvHuQpjI0wmcf8= +xorm.io/xorm v1.1.1/go.mod h1:Cb0DKYTHbyECMaSfgRnIZp5aiUgQozxcJJ0vzcLGJSg= diff --git a/integrations/api_pull_commits_test.go b/integrations/api_pull_commits_test.go new file mode 100644 index 0000000000000..30682d9c147ec --- /dev/null +++ b/integrations/api_pull_commits_test.go @@ -0,0 +1,37 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package integrations + +import ( + "net/http" + "testing" + + "code.gitea.io/gitea/models" + api "code.gitea.io/gitea/modules/structs" + "github.com/stretchr/testify/assert" +) + +func TestAPIPullCommits(t *testing.T) { + defer prepareTestEnv(t)() + pullIssue := models.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 2}).(*models.PullRequest) + assert.NoError(t, pullIssue.LoadIssue()) + repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: pullIssue.HeadRepoID}).(*models.Repository) + + session := loginUser(t, "user2") + req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/commits", repo.OwnerName, repo.Name, pullIssue.Index) + resp := session.MakeRequest(t, req, http.StatusOK) + + var commits []*api.Commit + DecodeJSON(t, resp, &commits) + + if !assert.Len(t, commits, 2) { + return + } + + assert.Equal(t, "5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", commits[0].SHA) + assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", commits[1].SHA) +} + +// TODO add tests for already merged PR and closed PR diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go index 7052e74b018ea..3948489f56fcf 100644 --- a/integrations/api_repo_test.go +++ b/integrations/api_repo_test.go @@ -495,6 +495,43 @@ func TestAPIRepoTransfer(t *testing.T) { _ = models.DeleteRepository(user, repo.OwnerID, repo.ID) } +func TestAPIGenerateRepo(t *testing.T) { + defer prepareTestEnv(t)() + + user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User) + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session) + + templateRepo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 44}).(*models.Repository) + + // user + repo := new(api.Repository) + req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/generate?token=%s", templateRepo.OwnerName, templateRepo.Name, token), &api.GenerateRepoOption{ + Owner: user.Name, + Name: "new-repo", + Description: "test generate repo", + Private: false, + GitContent: true, + }) + resp := session.MakeRequest(t, req, http.StatusCreated) + DecodeJSON(t, resp, repo) + + assert.Equal(t, "new-repo", repo.Name) + + // org + req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/generate?token=%s", templateRepo.OwnerName, templateRepo.Name, token), &api.GenerateRepoOption{ + Owner: "user3", + Name: "new-repo", + Description: "test generate repo", + Private: false, + GitContent: true, + }) + resp = session.MakeRequest(t, req, http.StatusCreated) + DecodeJSON(t, resp, repo) + + assert.Equal(t, "new-repo", repo.Name) +} + func TestAPIRepoGetReviewers(t *testing.T) { defer prepareTestEnv(t)() user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) diff --git a/integrations/api_user_search_test.go b/integrations/api_user_search_test.go index c5295fbba5dad..f7349827e5800 100644 --- a/integrations/api_user_search_test.go +++ b/integrations/api_user_search_test.go @@ -59,3 +59,34 @@ func TestAPIUserSearchNotLoggedIn(t *testing.T) { } } } + +func TestAPIUserSearchAdminLoggedInUserHidden(t *testing.T) { + defer prepareTestEnv(t)() + adminUsername := "user1" + session := loginUser(t, adminUsername) + token := getTokenForLoggedInUser(t, session) + query := "user31" + req := NewRequestf(t, "GET", "/api/v1/users/search?token=%s&q=%s", token, query) + req.SetBasicAuth(token, "x-oauth-basic") + resp := session.MakeRequest(t, req, http.StatusOK) + + var results SearchResults + DecodeJSON(t, resp, &results) + assert.NotEmpty(t, results.Data) + for _, user := range results.Data { + assert.Contains(t, user.UserName, query) + assert.NotEmpty(t, user.Email) + assert.EqualValues(t, "private", user.Visibility) + } +} + +func TestAPIUserSearchNotLoggedInUserHidden(t *testing.T) { + defer prepareTestEnv(t)() + query := "user31" + req := NewRequestf(t, "GET", "/api/v1/users/search?q=%s", query) + resp := MakeRequest(t, req, http.StatusOK) + + var results SearchResults + DecodeJSON(t, resp, &results) + assert.Empty(t, results.Data) +} diff --git a/integrations/download_test.go b/integrations/download_test.go index 305155e9ace48..38de75f476a96 100644 --- a/integrations/download_test.go +++ b/integrations/download_test.go @@ -8,6 +8,7 @@ import ( "net/http" "testing" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" ) @@ -62,3 +63,30 @@ func TestDownloadByIDMediaForSVGUsesSecureHeaders(t *testing.T) { assert.Equal(t, "image/svg+xml", resp.HeaderMap.Get("Content-Type")) assert.Equal(t, "nosniff", resp.HeaderMap.Get("X-Content-Type-Options")) } + +func TestDownloadRawTextFileWithoutMimeTypeMapping(t *testing.T) { + defer prepareTestEnv(t)() + + session := loginUser(t, "user2") + + req := NewRequest(t, "GET", "/user2/repo2/raw/branch/master/test.xml") + resp := session.MakeRequest(t, req, http.StatusOK) + + assert.Equal(t, "text/plain; charset=utf-8", resp.HeaderMap.Get("Content-Type")) +} + +func TestDownloadRawTextFileWithMimeTypeMapping(t *testing.T) { + defer prepareTestEnv(t)() + setting.MimeTypeMap.Map[".xml"] = "text/xml" + setting.MimeTypeMap.Enabled = true + + session := loginUser(t, "user2") + + req := NewRequest(t, "GET", "/user2/repo2/raw/branch/master/test.xml") + resp := session.MakeRequest(t, req, http.StatusOK) + + assert.Equal(t, "text/xml; charset=utf-8", resp.HeaderMap.Get("Content-Type")) + + delete(setting.MimeTypeMap.Map, ".xml") + setting.MimeTypeMap.Enabled = false +} diff --git a/integrations/git_test.go b/integrations/git_test.go index 13a60076a7e9e..a9848eaa4c309 100644 --- a/integrations/git_test.go +++ b/integrations/git_test.go @@ -143,7 +143,7 @@ func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) { t.Run("LFS", func(t *testing.T) { defer PrintCurrentTest(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -213,7 +213,7 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Length) - setting.CheckLFSVersion() + git.CheckLFSVersion() if setting.LFS.StartServer { req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS)) resp := session.MakeRequest(t, req, http.StatusOK) @@ -255,7 +255,7 @@ func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Length) - setting.CheckLFSVersion() + git.CheckLFSVersion() if setting.LFS.StartServer { req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS)) resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) diff --git a/integrations/gitea-repositories-meta/user2/repo2.git/objects/10/32bbf17fbc0d9c95bb5418dabe8f8c99278700 b/integrations/gitea-repositories-meta/user2/repo2.git/objects/10/32bbf17fbc0d9c95bb5418dabe8f8c99278700 new file mode 100644 index 0000000000000..736e40878edf4 --- /dev/null +++ b/integrations/gitea-repositories-meta/user2/repo2.git/objects/10/32bbf17fbc0d9c95bb5418dabe8f8c99278700 @@ -0,0 +1,2 @@ +x��K +�0Eg� %��":u��􊕦J|������p˭�Q��~% �9ل����G6G� �ͦw(��E4}*���{�)`YƆ�l�e�MJO�ܚ>�����%��^��ݿ�L�!]�N[v#E�6�U~/���0 Z��U'�gpJ5 \ No newline at end of file diff --git a/integrations/gitea-repositories-meta/user2/repo2.git/objects/26/f842bcad37fa40a1bb34cbb5ee219ee35d863d b/integrations/gitea-repositories-meta/user2/repo2.git/objects/26/f842bcad37fa40a1bb34cbb5ee219ee35d863d new file mode 100644 index 0000000000000..c3e7e778c5bc1 Binary files /dev/null and b/integrations/gitea-repositories-meta/user2/repo2.git/objects/26/f842bcad37fa40a1bb34cbb5ee219ee35d863d differ diff --git a/integrations/gitea-repositories-meta/user2/repo2.git/objects/ba/1aed4e2ea2443d76cec241b96be4ec990852ec b/integrations/gitea-repositories-meta/user2/repo2.git/objects/ba/1aed4e2ea2443d76cec241b96be4ec990852ec new file mode 100644 index 0000000000000..add9a3af0d4c3 Binary files /dev/null and b/integrations/gitea-repositories-meta/user2/repo2.git/objects/ba/1aed4e2ea2443d76cec241b96be4ec990852ec differ diff --git a/integrations/gitea-repositories-meta/user2/repo2.git/refs/heads/master b/integrations/gitea-repositories-meta/user2/repo2.git/refs/heads/master index 10967a9b8a0b9..334d09ca02155 100644 --- a/integrations/gitea-repositories-meta/user2/repo2.git/refs/heads/master +++ b/integrations/gitea-repositories-meta/user2/repo2.git/refs/heads/master @@ -1 +1 @@ -205ac761f3326a7ebe416e8673760016450b5cec +1032bbf17fbc0d9c95bb5418dabe8f8c99278700 diff --git a/integrations/integration_test.go b/integrations/integration_test.go index d755977d1ab16..8a008ac621760 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/queue" @@ -162,7 +163,7 @@ func initIntegrationTest() { setting.SetCustomPathAndConf("", "", "") setting.NewContext() util.RemoveAll(models.LocalCopyPath()) - setting.CheckLFSVersion() + git.CheckLFSVersion() setting.InitDBConfig() if err := storage.Init(); err != nil { fmt.Printf("Init storage failed: %v", err) diff --git a/integrations/lfs_getobject_test.go b/integrations/lfs_getobject_test.go index 337a93567a49f..c99500f469ea8 100644 --- a/integrations/lfs_getobject_test.go +++ b/integrations/lfs_getobject_test.go @@ -13,6 +13,7 @@ import ( "testing" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/web" @@ -81,7 +82,7 @@ func checkResponseTestContentEncoding(t *testing.T, content *[]byte, resp *httpt func TestGetLFSSmall(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -94,7 +95,7 @@ func TestGetLFSSmall(t *testing.T) { func TestGetLFSLarge(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -110,7 +111,7 @@ func TestGetLFSLarge(t *testing.T) { func TestGetLFSGzip(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -131,7 +132,7 @@ func TestGetLFSGzip(t *testing.T) { func TestGetLFSZip(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -154,7 +155,7 @@ func TestGetLFSZip(t *testing.T) { func TestGetLFSRangeNo(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return @@ -167,7 +168,7 @@ func TestGetLFSRangeNo(t *testing.T) { func TestGetLFSRange(t *testing.T) { defer prepareTestEnv(t)() - setting.CheckLFSVersion() + git.CheckLFSVersion() if !setting.LFS.StartServer { t.Skip() return diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go index 852c0b737c2da..209ff5a058f43 100644 --- a/integrations/migration-test/migration_test.go +++ b/integrations/migration-test/migration_test.go @@ -23,6 +23,7 @@ import ( "code.gitea.io/gitea/models/migrations" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -61,7 +62,7 @@ func initMigrationTest(t *testing.T) func() { assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, util.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) - setting.CheckLFSVersion() + git.CheckLFSVersion() setting.InitDBConfig() setting.NewLogServices(true) return deferFn diff --git a/models/convert.go b/models/convert.go index baa63bb388396..1deb7c66fbbda 100644 --- a/models/convert.go +++ b/models/convert.go @@ -8,10 +8,16 @@ import ( "fmt" "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm/schemas" ) // ConvertUtf8ToUtf8mb4 converts database and tables from utf8 to utf8mb4 if it's mysql and set ROW_FORMAT=dynamic func ConvertUtf8ToUtf8mb4() error { + if x.Dialect().URI().DBType != schemas.MYSQL { + return nil + } + _, err := x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", setting.Database.Name)) if err != nil { return err diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml index d903a7942f81b..850ee4041d81a 100644 --- a/models/fixtures/user.yml +++ b/models/fixtures/user.yml @@ -508,7 +508,6 @@ num_repos: 0 is_active: true - - id: 30 lower_name: user30 @@ -525,3 +524,20 @@ avatar_email: user30@example.com num_repos: 2 is_active: true + +- + id: 31 + lower_name: user31 + name: user31 + full_name: "user31" + email: user31@example.com + passwd_hash_algo: argon2 + passwd: a3d5fcd92bae586c2e3dbe72daea7a0d27833a8d0227aa1704f4bbd775c1f3b03535b76dd93b0d4d8d22a519dca47df1547b # password + type: 0 # individual + salt: ZogKvWdyEx + is_admin: false + visibility: 2 + avatar: avatar31 + avatar_email: user31@example.com + num_repos: 0 + is_active: true diff --git a/models/list_options.go b/models/list_options.go index 9cccd05465afe..ff02933f9bac4 100644 --- a/models/list_options.go +++ b/models/list_options.go @@ -41,7 +41,7 @@ func (opts *ListOptions) setEnginePagination(e Engine) Engine { func (opts *ListOptions) GetStartEnd() (start, end int) { opts.setDefaultValues() start = (opts.Page - 1) * opts.PageSize - end = start + opts.Page + end = start + opts.PageSize return } diff --git a/models/login_source.go b/models/login_source.go index 359b562b65054..7ff7e994eafb0 100644 --- a/models/login_source.go +++ b/models/login_source.go @@ -70,6 +70,17 @@ var ( _ convert.Conversion = &SSPIConfig{} ) +// jsonUnmarshalIgnoreErroneousBOM - due to a bug in xorm (see https://gitea.com/xorm/xorm/pulls/1957) - it's +// possible that a Blob may gain an unwanted prefix of 0xff 0xfe. +func jsonUnmarshalIgnoreErroneousBOM(bs []byte, v interface{}) error { + json := jsoniter.ConfigCompatibleWithStandardLibrary + err := json.Unmarshal(bs, &v) + if err != nil && len(bs) > 2 && bs[0] == 0xff && bs[1] == 0xfe { + err = json.Unmarshal(bs[2:], &v) + } + return err +} + // LDAPConfig holds configuration for LDAP login source. type LDAPConfig struct { *ldap.Source @@ -77,8 +88,7 @@ type LDAPConfig struct { // FromDB fills up a LDAPConfig from serialized format. func (cfg *LDAPConfig) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - err := json.Unmarshal(bs, &cfg) + err := jsonUnmarshalIgnoreErroneousBOM(bs, &cfg) if err != nil { return err } @@ -119,8 +129,7 @@ type SMTPConfig struct { // FromDB fills up an SMTPConfig from serialized format. func (cfg *SMTPConfig) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - return json.Unmarshal(bs, cfg) + return jsonUnmarshalIgnoreErroneousBOM(bs, cfg) } // ToDB exports an SMTPConfig to a serialized format. @@ -137,8 +146,7 @@ type PAMConfig struct { // FromDB fills up a PAMConfig from serialized format. func (cfg *PAMConfig) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - return json.Unmarshal(bs, &cfg) + return jsonUnmarshalIgnoreErroneousBOM(bs, cfg) } // ToDB exports a PAMConfig to a serialized format. @@ -159,8 +167,7 @@ type OAuth2Config struct { // FromDB fills up an OAuth2Config from serialized format. func (cfg *OAuth2Config) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - return json.Unmarshal(bs, cfg) + return jsonUnmarshalIgnoreErroneousBOM(bs, cfg) } // ToDB exports an SMTPConfig to a serialized format. @@ -180,8 +187,7 @@ type SSPIConfig struct { // FromDB fills up an SSPIConfig from serialized format. func (cfg *SSPIConfig) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - return json.Unmarshal(bs, cfg) + return jsonUnmarshalIgnoreErroneousBOM(bs, cfg) } // ToDB exports an SSPIConfig to a serialized format. diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 978ba6368f958..0e8b0d0e3db5f 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -323,6 +323,8 @@ var migrations = []Migration{ NewMigration("Add new table repo_archiver", addRepoArchiver), // v186 -> v187 NewMigration("Create protected tag table", createProtectedTagTable), + // v187 -> v188 + NewMigration("Drop unneeded webhook related columns", dropWebhookColumns), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/migrations_test.go b/models/migrations/migrations_test.go index 641d972b8b377..26066580d8978 100644 --- a/models/migrations/migrations_test.go +++ b/models/migrations/migrations_test.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -55,7 +56,7 @@ func TestMain(m *testing.M) { setting.SetCustomPathAndConf("", "", "") setting.NewContext() - setting.CheckLFSVersion() + git.CheckLFSVersion() setting.InitDBConfig() setting.NewLogServices(true) diff --git a/models/migrations/v187.go b/models/migrations/v187.go new file mode 100644 index 0000000000000..627423717a308 --- /dev/null +++ b/models/migrations/v187.go @@ -0,0 +1,46 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "xorm.io/xorm" +) + +func dropWebhookColumns(x *xorm.Engine) error { + // Make sure the columns exist before dropping them + type Webhook struct { + Signature string `xorm:"TEXT"` + IsSSL bool `xorm:"is_ssl"` + } + if err := x.Sync2(new(Webhook)); err != nil { + return err + } + + type HookTask struct { + Typ string `xorm:"VARCHAR(16) index"` + URL string `xorm:"TEXT"` + Signature string `xorm:"TEXT"` + HTTPMethod string `xorm:"http_method"` + ContentType int + IsSSL bool + } + if err := x.Sync2(new(HookTask)); err != nil { + return err + } + + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + if err := dropTableColumns(sess, "webhook", "signature", "is_ssl"); err != nil { + return err + } + if err := dropTableColumns(sess, "hook_task", "typ", "url", "signature", "http_method", "content_type", "is_ssl"); err != nil { + return err + } + + return sess.Commit() +} diff --git a/models/org.go b/models/org.go index 7f9e3cce5b624..073b26c2f8b69 100644 --- a/models/org.go +++ b/models/org.go @@ -455,22 +455,22 @@ func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) { Find(&orgs) } -// HasOrgVisible tells if the given user can see the given org -func HasOrgVisible(org, user *User) bool { - return hasOrgVisible(x, org, user) +// HasOrgOrUserVisible tells if the given user can see the given org or user +func HasOrgOrUserVisible(org, user *User) bool { + return hasOrgOrUserVisible(x, org, user) } -func hasOrgVisible(e Engine, org, user *User) bool { +func hasOrgOrUserVisible(e Engine, orgOrUser, user *User) bool { // Not SignedUser if user == nil { - return org.Visibility == structs.VisibleTypePublic + return orgOrUser.Visibility == structs.VisibleTypePublic } - if user.IsAdmin { + if user.IsAdmin || orgOrUser.ID == user.ID { return true } - if (org.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !org.hasMemberWithUserID(e, user.ID) { + if (orgOrUser.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !orgOrUser.hasMemberWithUserID(e, user.ID) { return false } return true @@ -483,7 +483,7 @@ func HasOrgsVisible(orgs []*User, user *User) bool { } for _, org := range orgs { - if HasOrgVisible(org, user) { + if HasOrgOrUserVisible(org, user) { return true } } diff --git a/models/org_test.go b/models/org_test.go index bed7a6eb8632f..e494e502dd31e 100644 --- a/models/org_test.go +++ b/models/org_test.go @@ -586,9 +586,9 @@ func TestHasOrgVisibleTypePublic(t *testing.T) { assert.NoError(t, CreateOrganization(org, owner)) org = AssertExistsAndLoadBean(t, &User{Name: org.Name, Type: UserTypeOrganization}).(*User) - test1 := HasOrgVisible(org, owner) - test2 := HasOrgVisible(org, user3) - test3 := HasOrgVisible(org, nil) + test1 := HasOrgOrUserVisible(org, owner) + test2 := HasOrgOrUserVisible(org, user3) + test3 := HasOrgOrUserVisible(org, nil) assert.True(t, test1) // owner of org assert.True(t, test2) // user not a part of org assert.True(t, test3) // logged out user @@ -609,9 +609,9 @@ func TestHasOrgVisibleTypeLimited(t *testing.T) { assert.NoError(t, CreateOrganization(org, owner)) org = AssertExistsAndLoadBean(t, &User{Name: org.Name, Type: UserTypeOrganization}).(*User) - test1 := HasOrgVisible(org, owner) - test2 := HasOrgVisible(org, user3) - test3 := HasOrgVisible(org, nil) + test1 := HasOrgOrUserVisible(org, owner) + test2 := HasOrgOrUserVisible(org, user3) + test3 := HasOrgOrUserVisible(org, nil) assert.True(t, test1) // owner of org assert.True(t, test2) // user not a part of org assert.False(t, test3) // logged out user @@ -632,9 +632,9 @@ func TestHasOrgVisibleTypePrivate(t *testing.T) { assert.NoError(t, CreateOrganization(org, owner)) org = AssertExistsAndLoadBean(t, &User{Name: org.Name, Type: UserTypeOrganization}).(*User) - test1 := HasOrgVisible(org, owner) - test2 := HasOrgVisible(org, user3) - test3 := HasOrgVisible(org, nil) + test1 := HasOrgOrUserVisible(org, owner) + test2 := HasOrgOrUserVisible(org, user3) + test3 := HasOrgOrUserVisible(org, nil) assert.True(t, test1) // owner of org assert.False(t, test2) // user not a part of org assert.False(t, test3) // logged out user diff --git a/models/repo.go b/models/repo.go index 4ce3d4839bc3c..009e7a457d074 100644 --- a/models/repo.go +++ b/models/repo.go @@ -585,8 +585,7 @@ func (repo *Repository) getReviewers(e Engine, doerID, posterID int64) ([]*User, var users []*User - if repo.IsPrivate || - (repo.Owner.IsOrganization() && repo.Owner.Visibility == api.VisibleTypePrivate) { + if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate { // This a private repository: // Anyone who can read the repository is a requestable reviewer if err := e. @@ -1036,7 +1035,7 @@ func GetRepoInitFile(tp, name string) ([]byte, error) { var ( reservedRepoNames = []string{".", ".."} - reservedRepoPatterns = []string{"*.git", "*.wiki"} + reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"} ) // IsUsableRepoName returns true when repository is usable diff --git a/models/repo_permission.go b/models/repo_permission.go index 138613b2e92e3..4f043a58ccfae 100644 --- a/models/repo_permission.go +++ b/models/repo_permission.go @@ -176,9 +176,9 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss return } - // Prevent strangers from checking out public repo of private orginization - // Allow user if they are collaborator of a repo within a private orginization but not a member of the orginization itself - if repo.Owner.IsOrganization() && !hasOrgVisible(e, repo.Owner, user) && !isCollaborator { + // Prevent strangers from checking out public repo of private orginization/users + // Allow user if they are collaborator of a repo within a private user or a private organization but not a member of the organization itself + if !hasOrgOrUserVisible(e, repo.Owner, user) && !isCollaborator { perm.AccessMode = AccessModeNone return } diff --git a/models/repo_unit.go b/models/repo_unit.go index 1d54579a6e727..d8060d16a03c9 100644 --- a/models/repo_unit.go +++ b/models/repo_unit.go @@ -28,8 +28,7 @@ type UnitConfig struct{} // FromDB fills up a UnitConfig from serialized format. func (cfg *UnitConfig) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - return json.Unmarshal(bs, &cfg) + return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg) } // ToDB exports a UnitConfig to a serialized format. @@ -45,8 +44,7 @@ type ExternalWikiConfig struct { // FromDB fills up a ExternalWikiConfig from serialized format. func (cfg *ExternalWikiConfig) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - return json.Unmarshal(bs, &cfg) + return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg) } // ToDB exports a ExternalWikiConfig to a serialized format. @@ -64,8 +62,7 @@ type ExternalTrackerConfig struct { // FromDB fills up a ExternalTrackerConfig from serialized format. func (cfg *ExternalTrackerConfig) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - return json.Unmarshal(bs, &cfg) + return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg) } // ToDB exports a ExternalTrackerConfig to a serialized format. @@ -83,8 +80,7 @@ type IssuesConfig struct { // FromDB fills up a IssuesConfig from serialized format. func (cfg *IssuesConfig) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - return json.Unmarshal(bs, &cfg) + return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg) } // ToDB exports a IssuesConfig to a serialized format. @@ -107,8 +103,7 @@ type PullRequestsConfig struct { // FromDB fills up a PullRequestsConfig from serialized format. func (cfg *PullRequestsConfig) FromDB(bs []byte) error { - json := jsoniter.ConfigCompatibleWithStandardLibrary - return json.Unmarshal(bs, &cfg) + return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg) } // ToDB exports a PullRequestsConfig to a serialized format. diff --git a/models/user.go b/models/user.go index 5998341422197..ce96a144af25d 100644 --- a/models/user.go +++ b/models/user.go @@ -432,6 +432,62 @@ func (u *User) IsPasswordSet() bool { return len(u.Passwd) != 0 } +// IsVisibleToUser check if viewer is able to see user profile +func (u *User) IsVisibleToUser(viewer *User) bool { + return u.isVisibleToUser(x, viewer) +} + +func (u *User) isVisibleToUser(e Engine, viewer *User) bool { + if viewer != nil && viewer.IsAdmin { + return true + } + + switch u.Visibility { + case structs.VisibleTypePublic: + return true + case structs.VisibleTypeLimited: + if viewer == nil || viewer.IsRestricted { + return false + } + return true + case structs.VisibleTypePrivate: + if viewer == nil || viewer.IsRestricted { + return false + } + + // If they follow - they see each over + follower := IsFollowing(u.ID, viewer.ID) + if follower { + return true + } + + // Now we need to check if they in some organization together + count, err := x.Table("team_user"). + Where( + builder.And( + builder.Eq{"uid": viewer.ID}, + builder.Or( + builder.Eq{"org_id": u.ID}, + builder.In("org_id", + builder.Select("org_id"). + From("team_user", "t2"). + Where(builder.Eq{"uid": u.ID}))))). + Count(new(TeamUser)) + if err != nil { + return false + } + + if count < 0 { + // No common organization + return false + } + + // they are in an organization together + return true + } + return false +} + // IsOrganization returns true if user is actually a organization. func (u *User) IsOrganization() bool { return u.Type == UserTypeOrganization @@ -758,7 +814,7 @@ var ( "user", } - reservedUserPatterns = []string{"*.keys", "*.gpg"} + reservedUserPatterns = []string{"*.keys", "*.gpg", "*.rss", "*.atom"} ) // isUsableName checks if name is reserved or pattern of name is not allowed @@ -796,32 +852,47 @@ func IsUsableUsername(name string) error { return isUsableName(reservedUsernames, reservedUserPatterns, name) } +// CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation +type CreateUserOverwriteOptions struct { + Visibility structs.VisibleType +} + // CreateUser creates record of a new user. -func CreateUser(u *User) (err error) { +func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) { if err = IsUsableUsername(u.Name); err != nil { return err } + // set system defaults + u.KeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate + u.Visibility = setting.Service.DefaultUserVisibilityMode + u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation + u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification + u.MaxRepoCreation = -1 + u.Theme = setting.UI.DefaultTheme + + // overwrite defaults if set + if len(overwriteDefault) != 0 && overwriteDefault[0] != nil { + u.Visibility = overwriteDefault[0].Visibility + } + sess := x.NewSession() defer sess.Close() if err = sess.Begin(); err != nil { return err } - isExist, err := isUserExist(sess, 0, u.Name) - if err != nil { - return err - } else if isExist { - return ErrUserAlreadyExist{u.Name} - } + // validate data - if err = deleteUserRedirect(sess, u.Name); err != nil { + if err := validateUser(u); err != nil { return err } - u.Email = strings.ToLower(u.Email) - if err = ValidateEmail(u.Email); err != nil { + isExist, err := isUserExist(sess, 0, u.Name) + if err != nil { return err + } else if isExist { + return ErrUserAlreadyExist{u.Name} } isExist, err = isEmailUsed(sess, u.Email) @@ -831,7 +902,7 @@ func CreateUser(u *User) (err error) { return ErrEmailAlreadyUsed{u.Email} } - u.KeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate + // prepare for database u.LowerName = strings.ToLower(u.Name) u.AvatarEmail = u.Email @@ -841,10 +912,12 @@ func CreateUser(u *User) (err error) { if err = u.SetPassword(u.Passwd); err != nil { return err } - u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation - u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification - u.MaxRepoCreation = -1 - u.Theme = setting.UI.DefaultTheme + + // save changes to database + + if err = deleteUserRedirect(sess, u.Name); err != nil { + return err + } if _, err = sess.Insert(u); err != nil { return err @@ -989,12 +1062,22 @@ func checkDupEmail(e Engine, u *User) error { return nil } -func updateUser(e Engine, u *User) (err error) { +// validateUser check if user is valide to insert / update into database +func validateUser(u *User) error { + if !setting.Service.AllowedUserVisibilityModesSlice.IsAllowedVisibility(u.Visibility) { + return fmt.Errorf("visibility Mode not allowed: %s", u.Visibility.String()) + } + u.Email = strings.ToLower(u.Email) - if err = ValidateEmail(u.Email); err != nil { + return ValidateEmail(u.Email) +} + +func updateUser(e Engine, u *User) error { + if err := validateUser(u); err != nil { return err } - _, err = e.ID(u.ID).AllCols().Update(u) + + _, err := e.ID(u.ID).AllCols().Update(u) return err } @@ -1009,6 +1092,10 @@ func UpdateUserCols(u *User, cols ...string) error { } func updateUserCols(e Engine, u *User, cols ...string) error { + if err := validateUser(u); err != nil { + return err + } + _, err := e.ID(u.ID).Cols(cols...).Update(u) return err } @@ -1527,10 +1614,9 @@ func (opts *SearchUserOptions) toConds() builder.Cond { cond = cond.And(keywordCond) } + // If visibility filtered if len(opts.Visible) > 0 { cond = cond.And(builder.In("visibility", opts.Visible)) - } else { - cond = cond.And(builder.In("visibility", structs.VisibleTypePublic)) } if opts.Actor != nil { @@ -1543,16 +1629,27 @@ func (opts *SearchUserOptions) toConds() builder.Cond { exprCond = builder.Expr("org_user.org_id = \"user\".id") } - var accessCond builder.Cond - if !opts.Actor.IsRestricted { - accessCond = builder.Or( - builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))), - builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited)) - } else { - // restricted users only see orgs they are a member of - accessCond = builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}))) + // If Admin - they see all users! + if !opts.Actor.IsAdmin { + // Force visiblity for privacy + var accessCond builder.Cond + if !opts.Actor.IsRestricted { + accessCond = builder.Or( + builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))), + builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited)) + } else { + // restricted users only see orgs they are a member of + accessCond = builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}))) + } + // Don't forget about self + accessCond = accessCond.Or(builder.Eq{"id": opts.Actor.ID}) + cond = cond.And(accessCond) } - cond = cond.And(accessCond) + + } else { + // Force visiblity for privacy + // Not logged in - only public users + cond = cond.And(builder.In("visibility", structs.VisibleTypePublic)) } if opts.UID > 0 { diff --git a/models/user_mail.go b/models/user_mail.go index 2758dfb8e84f3..320f2cb05a325 100644 --- a/models/user_mail.go +++ b/models/user_mail.go @@ -316,7 +316,7 @@ type SearchEmailResult struct { // SearchEmails takes options i.e. keyword and part of email name to search, // it returns results in given range and number of total results. func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) { - var cond builder.Cond = builder.Eq{"user.`type`": UserTypeIndividual} + var cond builder.Cond = builder.Eq{"`user`.`type`": UserTypeIndividual} if len(opts.Keyword) > 0 { likeStr := "%" + strings.ToLower(opts.Keyword) + "%" cond = cond.And(builder.Or( diff --git a/models/user_test.go b/models/user_test.go index 39a1b3c989c05..34c465c586498 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -11,6 +11,7 @@ import ( "testing" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -189,6 +190,7 @@ func TestDeleteUser(t *testing.T) { func TestEmailNotificationPreferences(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) + for _, test := range []struct { expected string userID int64 @@ -467,3 +469,23 @@ ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ib } } } + +func TestUpdateUser(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) + + user.KeepActivityPrivate = true + assert.NoError(t, UpdateUser(user)) + user = AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) + assert.True(t, user.KeepActivityPrivate) + + setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, false} + user.KeepActivityPrivate = false + user.Visibility = structs.VisibleTypePrivate + assert.Error(t, UpdateUser(user)) + user = AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) + assert.True(t, user.KeepActivityPrivate) + + user.Email = "no mail@mail.org" + assert.Error(t, UpdateUser(user)) +} diff --git a/models/webhook.go b/models/webhook.go index 24510cc6f757b..29cfcf6ed4f60 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -109,6 +109,22 @@ type HookEvent struct { HookEvents `json:"events"` } +// HookType is the type of a webhook +type HookType = string + +// Types of webhooks +const ( + GITEA HookType = "gitea" + GOGS HookType = "gogs" + SLACK HookType = "slack" + DISCORD HookType = "discord" + DINGTALK HookType = "dingtalk" + TELEGRAM HookType = "telegram" + MSTEAMS HookType = "msteams" + FEISHU HookType = "feishu" + MATRIX HookType = "matrix" +) + // HookStatus is the status of a web hook type HookStatus int @@ -126,17 +142,15 @@ type Webhook struct { OrgID int64 `xorm:"INDEX"` IsSystemWebhook bool URL string `xorm:"url TEXT"` - Signature string `xorm:"TEXT"` HTTPMethod string `xorm:"http_method"` ContentType HookContentType Secret string `xorm:"TEXT"` Events string `xorm:"TEXT"` *HookEvent `xorm:"-"` - IsSSL bool `xorm:"is_ssl"` - IsActive bool `xorm:"INDEX"` - Type HookTaskType `xorm:"VARCHAR(16) 'type'"` - Meta string `xorm:"TEXT"` // store hook-specific attributes - LastStatus HookStatus // Last delivery status + IsActive bool `xorm:"INDEX"` + Type HookType `xorm:"VARCHAR(16) 'type'"` + Meta string `xorm:"TEXT"` // store hook-specific attributes + LastStatus HookStatus // Last delivery status CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` @@ -558,22 +572,6 @@ func copyDefaultWebhooksToRepo(e Engine, repoID int64) error { // \___|_ / \____/ \____/|__|_ \ |____| (____ /____ >__|_ \ // \/ \/ \/ \/ \/ -// HookTaskType is the type of an hook task -type HookTaskType = string - -// Types of hook tasks -const ( - GITEA HookTaskType = "gitea" - GOGS HookTaskType = "gogs" - SLACK HookTaskType = "slack" - DISCORD HookTaskType = "discord" - DINGTALK HookTaskType = "dingtalk" - TELEGRAM HookTaskType = "telegram" - MSTEAMS HookTaskType = "msteams" - FEISHU HookTaskType = "feishu" - MATRIX HookTaskType = "matrix" -) - // HookEventType is the type of an hook event type HookEventType string @@ -635,7 +633,9 @@ func (h HookEventType) Event() string { // HookRequest represents hook task request information. type HookRequest struct { - Headers map[string]string `json:"headers"` + URL string `json:"url"` + HTTPMethod string `json:"http_method"` + Headers map[string]string `json:"headers"` } // HookResponse represents hook task response information. @@ -651,15 +651,9 @@ type HookTask struct { RepoID int64 `xorm:"INDEX"` HookID int64 UUID string - Typ HookTaskType `xorm:"VARCHAR(16) index"` - URL string `xorm:"TEXT"` - Signature string `xorm:"TEXT"` api.Payloader `xorm:"-"` PayloadContent string `xorm:"TEXT"` - HTTPMethod string `xorm:"http_method"` - ContentType HookContentType EventType HookEventType - IsSSL bool IsDelivered bool Delivered int64 DeliveredString string `xorm:"-"` diff --git a/models/webhook_test.go b/models/webhook_test.go index 88b2d40a39203..cab44a120e3e3 100644 --- a/models/webhook_test.go +++ b/models/webhook_test.go @@ -207,8 +207,6 @@ func TestCreateHookTask(t *testing.T) { hookTask := &HookTask{ RepoID: 3, HookID: 3, - Typ: GITEA, - URL: "http://www.example.com/unit_test", Payloader: &api.PushPayload{}, } AssertNotExistsBean(t, hookTask) @@ -233,8 +231,6 @@ func TestCleanupHookTaskTable_PerWebhook_DeletesDelivered(t *testing.T) { hookTask := &HookTask{ RepoID: 3, HookID: 3, - Typ: GITEA, - URL: "http://www.example.com/unit_test", Payloader: &api.PushPayload{}, IsDelivered: true, Delivered: time.Now().UnixNano(), @@ -252,8 +248,6 @@ func TestCleanupHookTaskTable_PerWebhook_LeavesUndelivered(t *testing.T) { hookTask := &HookTask{ RepoID: 2, HookID: 4, - Typ: GITEA, - URL: "http://www.example.com/unit_test", Payloader: &api.PushPayload{}, IsDelivered: false, } @@ -270,8 +264,6 @@ func TestCleanupHookTaskTable_PerWebhook_LeavesMostRecentTask(t *testing.T) { hookTask := &HookTask{ RepoID: 2, HookID: 4, - Typ: GITEA, - URL: "http://www.example.com/unit_test", Payloader: &api.PushPayload{}, IsDelivered: true, Delivered: time.Now().UnixNano(), @@ -289,8 +281,6 @@ func TestCleanupHookTaskTable_OlderThan_DeletesDelivered(t *testing.T) { hookTask := &HookTask{ RepoID: 3, HookID: 3, - Typ: GITEA, - URL: "http://www.example.com/unit_test", Payloader: &api.PushPayload{}, IsDelivered: true, Delivered: time.Now().AddDate(0, 0, -8).UnixNano(), @@ -308,8 +298,6 @@ func TestCleanupHookTaskTable_OlderThan_LeavesUndelivered(t *testing.T) { hookTask := &HookTask{ RepoID: 2, HookID: 4, - Typ: GITEA, - URL: "http://www.example.com/unit_test", Payloader: &api.PushPayload{}, IsDelivered: false, } @@ -326,8 +314,6 @@ func TestCleanupHookTaskTable_OlderThan_LeavesTaskEarlierThanAgeToDelete(t *test hookTask := &HookTask{ RepoID: 2, HookID: 4, - Typ: GITEA, - URL: "http://www.example.com/unit_test", Payloader: &api.PushPayload{}, IsDelivered: true, Delivered: time.Now().AddDate(0, 0, -6).UnixNano(), diff --git a/modules/convert/git_commit.go b/modules/convert/git_commit.go index c647dd4e1843e..fd4f12ecfa6d5 100644 --- a/modules/convert/git_commit.go +++ b/modules/convert/git_commit.go @@ -155,8 +155,8 @@ func ToCommit(repo *models.Repository, commit *git.Commit, userCache map[string] URL: repo.APIURL() + "/git/commits/" + commit.ID.String(), Author: &api.CommitUser{ Identity: api.Identity{ - Name: commit.Committer.Name, - Email: commit.Committer.Email, + Name: commit.Author.Name, + Email: commit.Author.Email, }, Date: commit.Author.When.Format(time.RFC3339), }, diff --git a/modules/convert/notification.go b/modules/convert/notification.go index cc941678b6038..b0888ee09f0cf 100644 --- a/modules/convert/notification.go +++ b/modules/convert/notification.go @@ -27,7 +27,7 @@ func ToNotificationThread(n *models.Notification) *api.NotificationThread { //handle Subject switch n.Source { case models.NotificationSourceIssue: - result.Subject = &api.NotificationSubject{Type: "Issue"} + result.Subject = &api.NotificationSubject{Type: api.NotifySubjectIssue} if n.Issue != nil { result.Subject.Title = n.Issue.Title result.Subject.URL = n.Issue.APIURL() @@ -38,7 +38,7 @@ func ToNotificationThread(n *models.Notification) *api.NotificationThread { } } case models.NotificationSourcePullRequest: - result.Subject = &api.NotificationSubject{Type: "Pull"} + result.Subject = &api.NotificationSubject{Type: api.NotifySubjectPull} if n.Issue != nil { result.Subject.Title = n.Issue.Title result.Subject.URL = n.Issue.APIURL() @@ -55,13 +55,13 @@ func ToNotificationThread(n *models.Notification) *api.NotificationThread { } case models.NotificationSourceCommit: result.Subject = &api.NotificationSubject{ - Type: "Commit", + Type: api.NotifySubjectCommit, Title: n.CommitID, URL: n.Repository.HTMLURL() + "/commit/" + n.CommitID, } case models.NotificationSourceRepository: result.Subject = &api.NotificationSubject{ - Type: "Repository", + Type: api.NotifySubjectRepository, Title: n.Repository.FullName(), URL: n.Repository.Link(), } diff --git a/modules/convert/user.go b/modules/convert/user.go index 894be3bd4441e..164ffb71fd2e7 100644 --- a/modules/convert/user.go +++ b/modules/convert/user.go @@ -62,10 +62,14 @@ func toUser(user *models.User, signed, authed bool) *api.User { Following: user.NumFollowing, StarredRepos: user.NumStars, } + + result.Visibility = user.Visibility.String() + // hide primary email if API caller is anonymous or user keep email private if signed && (!user.KeepEmailPrivate || authed) { result.Email = user.Email } + // only site admin will get these information and possibly user himself if authed { result.IsAdmin = user.IsAdmin diff --git a/modules/convert/user_test.go b/modules/convert/user_test.go index 7837910ffecb3..679c4f98948ae 100644 --- a/modules/convert/user_test.go +++ b/modules/convert/user_test.go @@ -8,6 +8,7 @@ import ( "testing" "code.gitea.io/gitea/models" + api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" ) @@ -27,4 +28,11 @@ func TestUser_ToUser(t *testing.T) { apiUser = toUser(user1, false, false) assert.False(t, apiUser.IsAdmin) + assert.EqualValues(t, api.VisibleTypePublic.String(), apiUser.Visibility) + + user31 := models.AssertExistsAndLoadBean(t, &models.User{ID: 31, IsAdmin: false, Visibility: api.VisibleTypePrivate}).(*models.User) + + apiUser = toUser(user31, true, true) + assert.False(t, apiUser.IsAdmin) + assert.EqualValues(t, api.VisibleTypePrivate.String(), apiUser.Visibility) } diff --git a/modules/git/command.go b/modules/git/command.go index 2e375fd4f9f9c..d83c42fdc2183 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -23,8 +23,8 @@ var ( // GlobalCommandArgs global command args for external package setting GlobalCommandArgs []string - // DefaultCommandExecutionTimeout default command execution timeout duration - DefaultCommandExecutionTimeout = 360 * time.Second + // defaultCommandExecutionTimeout default command execution timeout duration + defaultCommandExecutionTimeout = 360 * time.Second ) // DefaultLocale is the default LC_ALL to run git commands in. @@ -111,7 +111,7 @@ func (c *Command) RunInDirTimeoutEnvFullPipeline(env []string, timeout time.Dura // it pipes stdout and stderr to given io.Writer and passes in an io.Reader as stdin. Between cmd.Start and cmd.Wait the passed in function is run. func (c *Command) RunInDirTimeoutEnvFullPipelineFunc(env []string, timeout time.Duration, dir string, stdout, stderr io.Writer, stdin io.Reader, fn func(context.Context, context.CancelFunc) error) error { if timeout == -1 { - timeout = DefaultCommandExecutionTimeout + timeout = defaultCommandExecutionTimeout } if len(dir) == 0 { @@ -199,7 +199,11 @@ func (c *Command) RunInDirTimeoutEnv(env []string, timeout time.Duration, dir st return nil, ConcatenateError(err, stderr.String()) } if stdout.Len() > 0 && log.IsTrace() { - log.Trace("Stdout:\n %s", stdout.Bytes()[:1024]) + tracelen := stdout.Len() + if tracelen > 1024 { + tracelen = 1024 + } + log.Trace("Stdout:\n %s", stdout.Bytes()[:tracelen]) } return stdout.Bytes(), nil } diff --git a/modules/git/commit.go b/modules/git/commit.go index f4d6075fe2d22..3ce2b03886d1f 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -15,6 +15,8 @@ import ( "os/exec" "strconv" "strings" + + "code.gitea.io/gitea/modules/log" ) // Commit represents a git commit. @@ -432,33 +434,59 @@ func NewCommitFileStatus() *CommitFileStatus { } } +func parseCommitFileStatus(fileStatus *CommitFileStatus, stdout io.Reader) { + rd := bufio.NewReader(stdout) + peek, err := rd.Peek(1) + if err != nil { + if err != io.EOF { + log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err) + } + return + } + if peek[0] == '\n' || peek[0] == '\x00' { + _, _ = rd.Discard(1) + } + for { + modifier, err := rd.ReadSlice('\x00') + if err != nil { + if err != io.EOF { + log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err) + } + return + } + file, err := rd.ReadString('\x00') + if err != nil { + if err != io.EOF { + log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err) + } + return + } + file = file[:len(file)-1] + switch modifier[0] { + case 'A': + fileStatus.Added = append(fileStatus.Added, file) + case 'D': + fileStatus.Removed = append(fileStatus.Removed, file) + case 'M': + fileStatus.Modified = append(fileStatus.Modified, file) + } + } +} + // GetCommitFileStatus returns file status of commit in given repository. func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) { stdout, w := io.Pipe() done := make(chan struct{}) fileStatus := NewCommitFileStatus() go func() { - scanner := bufio.NewScanner(stdout) - for scanner.Scan() { - fields := strings.Fields(scanner.Text()) - if len(fields) < 2 { - continue - } - - switch fields[0][0] { - case 'A': - fileStatus.Added = append(fileStatus.Added, fields[1]) - case 'D': - fileStatus.Removed = append(fileStatus.Removed, fields[1]) - case 'M': - fileStatus.Modified = append(fileStatus.Modified, fields[1]) - } - } - done <- struct{}{} + parseCommitFileStatus(fileStatus, stdout) + close(done) }() stderr := new(bytes.Buffer) - err := NewCommand("show", "--name-status", "--pretty=format:''", commitID).RunInDirPipeline(repoPath, w, stderr) + args := []string{"log", "--name-status", "-c", "--pretty=format:", "--parents", "--no-renames", "-z", "-1", commitID} + + err := NewCommand(args...).RunInDirPipeline(repoPath, w, stderr) w.Close() // Close writer to exit parsing goroutine if err != nil { return nil, ConcatenateError(err, stderr.String()) diff --git a/modules/git/commit_test.go b/modules/git/commit_test.go index 0925a6ce6ac1c..57132c00dc69c 100644 --- a/modules/git/commit_test.go +++ b/modules/git/commit_test.go @@ -130,3 +130,109 @@ func TestHasPreviousCommit(t *testing.T) { assert.NoError(t, err) assert.False(t, selfNot) } + +func TestParseCommitFileStatus(t *testing.T) { + type testcase struct { + output string + added []string + removed []string + modified []string + } + + kases := []testcase{ + { + // Merge commit + output: "MM\x00options/locale/locale_en-US.ini\x00", + modified: []string{ + "options/locale/locale_en-US.ini", + }, + added: []string{}, + removed: []string{}, + }, + { + // Spaces commit + output: "D\x00b\x00D\x00b b/b\x00A\x00b b/b b/b b/b\x00A\x00b b/b b/b b/b b/b\x00", + removed: []string{ + "b", + "b b/b", + }, + modified: []string{}, + added: []string{ + "b b/b b/b b/b", + "b b/b b/b b/b b/b", + }, + }, + { + // larger commit + output: "M\x00go.mod\x00M\x00go.sum\x00M\x00modules/ssh/ssh.go\x00M\x00vendor/github.com/gliderlabs/ssh/circle.yml\x00M\x00vendor/github.com/gliderlabs/ssh/context.go\x00A\x00vendor/github.com/gliderlabs/ssh/go.mod\x00A\x00vendor/github.com/gliderlabs/ssh/go.sum\x00M\x00vendor/github.com/gliderlabs/ssh/server.go\x00M\x00vendor/github.com/gliderlabs/ssh/session.go\x00M\x00vendor/github.com/gliderlabs/ssh/ssh.go\x00M\x00vendor/golang.org/x/sys/unix/mkerrors.sh\x00M\x00vendor/golang.org/x/sys/unix/syscall_darwin.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/zerrors_linux.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go\x00M\x00vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go\x00M\x00vendor/modules.txt\x00", + modified: []string{ + "go.mod", + "go.sum", + "modules/ssh/ssh.go", + "vendor/github.com/gliderlabs/ssh/circle.yml", + "vendor/github.com/gliderlabs/ssh/context.go", + "vendor/github.com/gliderlabs/ssh/server.go", + "vendor/github.com/gliderlabs/ssh/session.go", + "vendor/github.com/gliderlabs/ssh/ssh.go", + "vendor/golang.org/x/sys/unix/mkerrors.sh", + "vendor/golang.org/x/sys/unix/syscall_darwin.go", + "vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go", + "vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go", + "vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go", + "vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go", + "vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go", + "vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go", + "vendor/golang.org/x/sys/unix/zerrors_linux.go", + "vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go", + "vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go", + "vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go", + "vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go", + "vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go", + "vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go", + "vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go", + "vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go", + "vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go", + "vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go", + "vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go", + "vendor/modules.txt", + }, + added: []string{ + "vendor/github.com/gliderlabs/ssh/go.mod", + "vendor/github.com/gliderlabs/ssh/go.sum", + }, + removed: []string{}, + }, + { + // git 1.7.2 adds an unnecessary \x00 on merge commit + output: "\x00MM\x00options/locale/locale_en-US.ini\x00", + modified: []string{ + "options/locale/locale_en-US.ini", + }, + added: []string{}, + removed: []string{}, + }, + { + // git 1.7.2 adds an unnecessary \n on normal commit + output: "\nD\x00b\x00D\x00b b/b\x00A\x00b b/b b/b b/b\x00A\x00b b/b b/b b/b b/b\x00", + removed: []string{ + "b", + "b b/b", + }, + modified: []string{}, + added: []string{ + "b b/b b/b b/b", + "b b/b b/b b/b b/b", + }, + }, + } + + for _, kase := range kases { + fileStatus := NewCommitFileStatus() + parseCommitFileStatus(fileStatus, strings.NewReader(kase.output)) + + assert.Equal(t, kase.added, fileStatus.Added) + assert.Equal(t, kase.removed, fileStatus.Removed) + assert.Equal(t, kase.modified, fileStatus.Modified) + } + +} diff --git a/modules/git/git.go b/modules/git/git.go index ce1b15c95351f..ef6ec0c2bf32a 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -14,6 +14,7 @@ import ( "time" "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/setting" "github.com/hashicorp/go-version" ) @@ -106,10 +107,42 @@ func SetExecutablePath(path string) error { return nil } +// VersionInfo returns git version information +func VersionInfo() string { + var format = "Git Version: %s" + var args = []interface{}{gitVersion.Original()} + // Since git wire protocol has been released from git v2.18 + if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { + format += ", Wire Protocol %s Enabled" + args = append(args, "Version 2") // for focus color + } + + return fmt.Sprintf(format, args...) +} + // Init initializes git module func Init(ctx context.Context) error { DefaultContext = ctx + defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second + + if err := SetExecutablePath(setting.Git.Path); err != nil { + return err + } + + // force cleanup args + GlobalCommandArgs = []string{} + + if CheckGitVersionAtLeast("2.9") == nil { + // Explicitly disable credential helper, otherwise Git credentials might leak + GlobalCommandArgs = append(GlobalCommandArgs, "-c", "credential.helper=") + } + + // Since git wire protocol has been released from git v2.18 + if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { + GlobalCommandArgs = append(GlobalCommandArgs, "-c", "protocol.version=2") + } + // Save current git version on init to gitVersion otherwise it would require an RWMutex if err := LoadGitVersion(); err != nil { return err diff --git a/modules/git/last_commit_cache_nogogit.go b/modules/git/last_commit_cache_nogogit.go index ff9f9ff1cfadb..faf6e23fa8166 100644 --- a/modules/git/last_commit_cache_nogogit.go +++ b/modules/git/last_commit_cache_nogogit.go @@ -94,7 +94,8 @@ func (c *LastCommitCache) recursiveCache(ctx context.Context, commit *Commit, tr if err := c.Put(commit.ID.String(), path.Join(treePath, entry), entryCommit.ID.String()); err != nil { return err } - if entryMap[entry].IsDir() { + // entryMap won't contain "" therefore skip this. + if treeEntry := entryMap[entry]; treeEntry != nil && treeEntry.IsDir() { subTree, err := tree.SubTree(entry) if err != nil { return err diff --git a/modules/git/lfs.go b/modules/git/lfs.go new file mode 100644 index 0000000000000..79049c98245ad --- /dev/null +++ b/modules/git/lfs.go @@ -0,0 +1,37 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "sync" + + logger "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" +) + +var once sync.Once + +// CheckLFSVersion will check lfs version, if not satisfied, then disable it. +func CheckLFSVersion() { + if setting.LFS.StartServer { + //Disable LFS client hooks if installed for the current OS user + //Needs at least git v2.1.2 + + err := LoadGitVersion() + if err != nil { + logger.Fatal("Error retrieving git version: %v", err) + } + + if CheckGitVersionAtLeast("2.1.2") != nil { + setting.LFS.StartServer = false + logger.Error("LFS server support needs at least Git v2.1.2") + } else { + once.Do(func() { + GlobalCommandArgs = append(GlobalCommandArgs, "-c", "filter.lfs.required=", + "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") + }) + } + } +} diff --git a/modules/git/repo_base_gogit.go b/modules/git/repo_base_gogit.go index 19a3f84571fb6..6186824c0b9f6 100644 --- a/modules/git/repo_base_gogit.go +++ b/modules/git/repo_base_gogit.go @@ -12,6 +12,8 @@ import ( "path/filepath" gitealog "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "github.com/go-git/go-billy/v5/osfs" gogit "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/cache" @@ -46,7 +48,7 @@ func OpenRepository(repoPath string) (*Repository, error) { return nil, err } } - storage := filesystem.NewStorageWithOptions(fs, cache.NewObjectLRUDefault(), filesystem.Options{KeepDescriptors: true}) + storage := filesystem.NewStorageWithOptions(fs, cache.NewObjectLRUDefault(), filesystem.Options{KeepDescriptors: true, LargeObjectThreshold: setting.Git.LargeObjectThreshold}) gogitRepo, err := gogit.Open(storage, fs) if err != nil { return nil, err diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index 664a7445dd9dc..5b417cd77455c 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -12,6 +12,8 @@ import ( "io/ioutil" "strconv" "strings" + + "code.gitea.io/gitea/modules/setting" ) // GetBranchCommitID returns last commit ID string of given branch. @@ -85,12 +87,6 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) { return commits.Front().Value.(*Commit), nil } -// CommitsRangeSize the default commits range size -var CommitsRangeSize = 50 - -// BranchesRangeSize the default branches range size -var BranchesRangeSize = 20 - func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) (*list.List, error) { stdout, err := NewCommand("log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize), "--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunInDirBytes(repo.Path) @@ -206,7 +202,7 @@ func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) { // CommitsByFileAndRange return the commits according revison file and the page func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (*list.List, error) { - skip := (page - 1) * CommitsRangeSize + skip := (page - 1) * setting.Git.CommitsRangeSize stdoutReader, stdoutWriter := io.Pipe() defer func() { @@ -216,7 +212,7 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) ( go func() { stderr := strings.Builder{} err := NewCommand("log", revision, "--follow", - "--max-count="+strconv.Itoa(CommitsRangeSize*page), + "--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page), prettyLogFormat, "--", file). RunInDirPipeline(repo.Path, stdoutWriter, &stderr) if err != nil { @@ -247,7 +243,7 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) ( // CommitsByFileAndRangeNoFollow return the commits according revison file and the page func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, page int) (*list.List, error) { stdout, err := NewCommand("log", revision, "--skip="+strconv.Itoa((page-1)*50), - "--max-count="+strconv.Itoa(CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path) + "--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path) if err != nil { return nil, err } @@ -268,14 +264,15 @@ func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (in return len(strings.Split(stdout, "\n")) - 1, nil } -// CommitsBetween returns a list that contains commits between [last, before). +// CommitsBetween returns a list that contains commits between [before, last). +// If before is detached (removed by reset + push) it is not included. func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List, error) { var stdout []byte var err error if before == nil { stdout, err = NewCommand("rev-list", last.ID.String()).RunInDirBytes(repo.Path) } else { - stdout, err = NewCommand("rev-list", before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path) + stdout, err = NewCommand("rev-list", before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path) if err != nil && strings.Contains(err.Error(), "no merge base") { // future versions of git >= 2.28 are likely to return an error if before and last have become unrelated. // previously it would return the results of git rev-list before last so let's try that... @@ -288,14 +285,14 @@ func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List return repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout)) } -// CommitsBetweenLimit returns a list that contains at most limit commits skipping the first skip commits between [last, before) +// CommitsBetweenLimit returns a list that contains at most limit commits skipping the first skip commits between [before, last) func (repo *Repository) CommitsBetweenLimit(last *Commit, before *Commit, limit, skip int) (*list.List, error) { var stdout []byte var err error if before == nil { stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunInDirBytes(repo.Path) } else { - stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path) + stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path) if err != nil && strings.Contains(err.Error(), "no merge base") { // future versions of git >= 2.28 are likely to return an error if before and last have become unrelated. // previously it would return the results of git rev-list --max-count n before last so let's try that... @@ -326,7 +323,7 @@ func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, erro // CommitsCountBetween return numbers of commits between two commits func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) { - count, err := CommitsCountFiles(repo.Path, []string{start + "..." + end}, []string{}) + count, err := CommitsCountFiles(repo.Path, []string{start + ".." + end}, []string{}) if err != nil && strings.Contains(err.Error(), "no merge base") { // future versions of git >= 2.28 are likely to return an error if before and last have become unrelated. // previously it would return the results of git rev-list before last so let's try that... diff --git a/modules/git/repo_commit_test.go b/modules/git/repo_commit_test.go index 8f8acbdfed67e..a6c27ea4d55bd 100644 --- a/modules/git/repo_commit_test.go +++ b/modules/git/repo_commit_test.go @@ -78,3 +78,25 @@ func TestIsCommitInBranch(t *testing.T) { assert.NoError(t, err) assert.False(t, result) } + +func TestRepository_CommitsBetweenIDs(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo4_commitsbetween") + bareRepo1, err := OpenRepository(bareRepo1Path) + assert.NoError(t, err) + defer bareRepo1.Close() + + cases := []struct { + OldID string + NewID string + ExpectedCommits int + }{ + {"fdc1b615bdcff0f0658b216df0c9209e5ecb7c78", "78a445db1eac62fe15e624e1137965969addf344", 1}, //com1 -> com2 + {"78a445db1eac62fe15e624e1137965969addf344", "fdc1b615bdcff0f0658b216df0c9209e5ecb7c78", 0}, //reset HEAD~, com2 -> com1 + {"78a445db1eac62fe15e624e1137965969addf344", "a78e5638b66ccfe7e1b4689d3d5684e42c97d7ca", 1}, //com2 -> com2_new + } + for i, c := range cases { + commits, err := bareRepo1.CommitsBetweenIDs(c.NewID, c.OldID) + assert.NoError(t, err) + assert.Equal(t, c.ExpectedCommits, commits.Len(), "case %d", i) + } +} diff --git a/modules/git/tests/repos/repo4_commitsbetween/HEAD b/modules/git/tests/repos/repo4_commitsbetween/HEAD new file mode 100644 index 0000000000000..b870d82622c1a --- /dev/null +++ b/modules/git/tests/repos/repo4_commitsbetween/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/modules/git/tests/repos/repo4_commitsbetween/config b/modules/git/tests/repos/repo4_commitsbetween/config new file mode 100644 index 0000000000000..d545cdabdbdda --- /dev/null +++ b/modules/git/tests/repos/repo4_commitsbetween/config @@ -0,0 +1,7 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = false + logallrefupdates = true + symlinks = false + ignorecase = true diff --git a/modules/git/tests/repos/repo4_commitsbetween/logs/HEAD b/modules/git/tests/repos/repo4_commitsbetween/logs/HEAD new file mode 100644 index 0000000000000..24cc684baef23 --- /dev/null +++ b/modules/git/tests/repos/repo4_commitsbetween/logs/HEAD @@ -0,0 +1,4 @@ +0000000000000000000000000000000000000000 fdc1b615bdcff0f0658b216df0c9209e5ecb7c78 KN4CK3R 1624915979 +0200 commit (initial): com1 +fdc1b615bdcff0f0658b216df0c9209e5ecb7c78 78a445db1eac62fe15e624e1137965969addf344 KN4CK3R 1624915993 +0200 commit: com2 +78a445db1eac62fe15e624e1137965969addf344 fdc1b615bdcff0f0658b216df0c9209e5ecb7c78 KN4CK3R 1624916008 +0200 reset: moving to HEAD~1 +fdc1b615bdcff0f0658b216df0c9209e5ecb7c78 a78e5638b66ccfe7e1b4689d3d5684e42c97d7ca KN4CK3R 1624916029 +0200 commit: com2_new diff --git a/modules/git/tests/repos/repo4_commitsbetween/logs/refs/heads/main b/modules/git/tests/repos/repo4_commitsbetween/logs/refs/heads/main new file mode 100644 index 0000000000000..24cc684baef23 --- /dev/null +++ b/modules/git/tests/repos/repo4_commitsbetween/logs/refs/heads/main @@ -0,0 +1,4 @@ +0000000000000000000000000000000000000000 fdc1b615bdcff0f0658b216df0c9209e5ecb7c78 KN4CK3R 1624915979 +0200 commit (initial): com1 +fdc1b615bdcff0f0658b216df0c9209e5ecb7c78 78a445db1eac62fe15e624e1137965969addf344 KN4CK3R 1624915993 +0200 commit: com2 +78a445db1eac62fe15e624e1137965969addf344 fdc1b615bdcff0f0658b216df0c9209e5ecb7c78 KN4CK3R 1624916008 +0200 reset: moving to HEAD~1 +fdc1b615bdcff0f0658b216df0c9209e5ecb7c78 a78e5638b66ccfe7e1b4689d3d5684e42c97d7ca KN4CK3R 1624916029 +0200 commit: com2_new diff --git a/modules/git/tests/repos/repo4_commitsbetween/objects/27/734c860ab19650d48e71f9f12d9bd194ed82ea b/modules/git/tests/repos/repo4_commitsbetween/objects/27/734c860ab19650d48e71f9f12d9bd194ed82ea new file mode 100644 index 0000000000000..5b26f8b3a8c10 Binary files /dev/null and b/modules/git/tests/repos/repo4_commitsbetween/objects/27/734c860ab19650d48e71f9f12d9bd194ed82ea differ diff --git a/modules/git/tests/repos/repo4_commitsbetween/objects/56/a6051ca2b02b04ef92d5150c9ef600403cb1de b/modules/git/tests/repos/repo4_commitsbetween/objects/56/a6051ca2b02b04ef92d5150c9ef600403cb1de new file mode 100644 index 0000000000000..b17dfe30e64f2 Binary files /dev/null and b/modules/git/tests/repos/repo4_commitsbetween/objects/56/a6051ca2b02b04ef92d5150c9ef600403cb1de differ diff --git a/modules/git/tests/repos/repo4_commitsbetween/objects/78/a445db1eac62fe15e624e1137965969addf344 b/modules/git/tests/repos/repo4_commitsbetween/objects/78/a445db1eac62fe15e624e1137965969addf344 new file mode 100644 index 0000000000000..6d23de052ee77 --- /dev/null +++ b/modules/git/tests/repos/repo4_commitsbetween/objects/78/a445db1eac62fe15e624e1137965969addf344 @@ -0,0 +1,3 @@ +x��M +�0@a�=E��̤I������$�Zl�����|�G���)�îm̊uO�"����&`�8Gt�I�7�#n�6%�09�)�8�F�(hl��@���MuS��\����1�y=�%?i�u�"��O +��Dm�ڃ��w���ź{p�C_ \ No newline at end of file diff --git a/modules/git/tests/repos/repo4_commitsbetween/objects/a7/8e5638b66ccfe7e1b4689d3d5684e42c97d7ca b/modules/git/tests/repos/repo4_commitsbetween/objects/a7/8e5638b66ccfe7e1b4689d3d5684e42c97d7ca new file mode 100644 index 0000000000000..d5c554a542dc6 Binary files /dev/null and b/modules/git/tests/repos/repo4_commitsbetween/objects/a7/8e5638b66ccfe7e1b4689d3d5684e42c97d7ca differ diff --git a/modules/git/tests/repos/repo4_commitsbetween/objects/ad/74ceca1b8fde10c7d933bd2e56d347dddb4ab5 b/modules/git/tests/repos/repo4_commitsbetween/objects/ad/74ceca1b8fde10c7d933bd2e56d347dddb4ab5 new file mode 100644 index 0000000000000..26ed785006120 Binary files /dev/null and b/modules/git/tests/repos/repo4_commitsbetween/objects/ad/74ceca1b8fde10c7d933bd2e56d347dddb4ab5 differ diff --git a/modules/git/tests/repos/repo4_commitsbetween/objects/b5/d8dd0ddd9d8d752bb47b5f781f09f478316098 b/modules/git/tests/repos/repo4_commitsbetween/objects/b5/d8dd0ddd9d8d752bb47b5f781f09f478316098 new file mode 100644 index 0000000000000..8060b57df0376 Binary files /dev/null and b/modules/git/tests/repos/repo4_commitsbetween/objects/b5/d8dd0ddd9d8d752bb47b5f781f09f478316098 differ diff --git a/modules/git/tests/repos/repo4_commitsbetween/objects/d8/263ee9860594d2806b0dfd1bfd17528b0ba2a4 b/modules/git/tests/repos/repo4_commitsbetween/objects/d8/263ee9860594d2806b0dfd1bfd17528b0ba2a4 new file mode 100644 index 0000000000000..4b1baefffb3b6 Binary files /dev/null and b/modules/git/tests/repos/repo4_commitsbetween/objects/d8/263ee9860594d2806b0dfd1bfd17528b0ba2a4 differ diff --git a/modules/git/tests/repos/repo4_commitsbetween/objects/e2/3cc6a008501f1491b0480cedaef160e41cf684 b/modules/git/tests/repos/repo4_commitsbetween/objects/e2/3cc6a008501f1491b0480cedaef160e41cf684 new file mode 100644 index 0000000000000..0a70530845aa7 Binary files /dev/null and b/modules/git/tests/repos/repo4_commitsbetween/objects/e2/3cc6a008501f1491b0480cedaef160e41cf684 differ diff --git a/modules/git/tests/repos/repo4_commitsbetween/objects/fd/c1b615bdcff0f0658b216df0c9209e5ecb7c78 b/modules/git/tests/repos/repo4_commitsbetween/objects/fd/c1b615bdcff0f0658b216df0c9209e5ecb7c78 new file mode 100644 index 0000000000000..2e6d94584ca3e Binary files /dev/null and b/modules/git/tests/repos/repo4_commitsbetween/objects/fd/c1b615bdcff0f0658b216df0c9209e5ecb7c78 differ diff --git a/modules/git/tests/repos/repo4_commitsbetween/refs/heads/main b/modules/git/tests/repos/repo4_commitsbetween/refs/heads/main new file mode 100644 index 0000000000000..9e1b981a6ecf4 --- /dev/null +++ b/modules/git/tests/repos/repo4_commitsbetween/refs/heads/main @@ -0,0 +1 @@ +a78e5638b66ccfe7e1b4689d3d5684e42c97d7ca diff --git a/modules/markup/external/external.go b/modules/markup/external/external.go index c849f505e7ee8..e35a1b99c0fd8 100644 --- a/modules/markup/external/external.go +++ b/modules/markup/external/external.go @@ -5,6 +5,7 @@ package external import ( + "context" "fmt" "io" "io/ioutil" @@ -15,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -96,7 +98,13 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io. args = append(args, f.Name()) } - cmd := exec.Command(commands[0], args...) + processCtx, cancel := context.WithCancel(ctx.Ctx) + defer cancel() + + pid := process.GetManager().Add(fmt.Sprintf("Render [%s] for %s", commands[0], ctx.URLPrefix), cancel) + defer process.GetManager().Remove(pid) + + cmd := exec.CommandContext(processCtx, commands[0], args...) cmd.Env = append( os.Environ(), "GITEA_PREFIX_SRC="+ctx.URLPrefix, diff --git a/modules/markup/html.go b/modules/markup/html.go index 0cc0e23b5c57d..7afd8114c1b32 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -6,7 +6,6 @@ package markup import ( "bytes" - "fmt" "io" "io/ioutil" "net/url" @@ -66,7 +65,7 @@ var ( blackfridayExtRegex = regexp.MustCompile(`[^:]*:user-content-`) // EmojiShortCodeRegex find emoji by alias like :smile: - EmojiShortCodeRegex = regexp.MustCompile(`\:[\w\+\-]+\:{1}`) + EmojiShortCodeRegex = regexp.MustCompile(`:[\w\+\-]+:`) ) // CSS class for action keywords (e.g. "closes: #1") @@ -365,7 +364,7 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node, visitText } case html.ElementNode: if node.Data == "img" { - for _, attr := range node.Attr { + for i, attr := range node.Attr { if attr.Key != "src" { continue } @@ -378,6 +377,7 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node, visitText attr.Val = util.URLJoin(prefix, attr.Val) } + node.Attr[i] = attr } } else if node.Data == "a" { visitText = false @@ -460,17 +460,14 @@ func createEmoji(content, class, name string) *html.Node { return span } -func createCustomEmoji(alias, class string) *html.Node { - +func createCustomEmoji(alias string) *html.Node { span := &html.Node{ Type: html.ElementNode, Data: atom.Span.String(), Attr: []html.Attribute{}, } - if class != "" { - span.Attr = append(span.Attr, html.Attribute{Key: "class", Val: class}) - span.Attr = append(span.Attr, html.Attribute{Key: "aria-label", Val: alias}) - } + span.Attr = append(span.Attr, html.Attribute{Key: "class", Val: "emoji"}) + span.Attr = append(span.Attr, html.Attribute{Key: "aria-label", Val: alias}) img := &html.Node{ Type: html.ElementNode, @@ -478,10 +475,8 @@ func createCustomEmoji(alias, class string) *html.Node { Data: "img", Attr: []html.Attribute{}, } - if class != "" { - img.Attr = append(img.Attr, html.Attribute{Key: "alt", Val: fmt.Sprintf(`:%s:`, alias)}) - img.Attr = append(img.Attr, html.Attribute{Key: "src", Val: fmt.Sprintf(`%s/assets/img/emoji/%s.png`, setting.StaticURLPrefix, alias)}) - } + img.Attr = append(img.Attr, html.Attribute{Key: "alt", Val: ":" + alias + ":"}) + img.Attr = append(img.Attr, html.Attribute{Key: "src", Val: setting.StaticURLPrefix + "/assets/img/emoji/" + alias + ".png"}) span.AppendChild(img) return span @@ -948,9 +943,8 @@ func emojiShortCodeProcessor(ctx *RenderContext, node *html.Node) { converted := emoji.FromAlias(alias) if converted == nil { // check if this is a custom reaction - s := strings.Join(setting.UI.Reactions, " ") + "gitea" - if strings.Contains(s, alias) { - replaceContent(node, m[0], m[1], createCustomEmoji(alias, "emoji")) + if _, exist := setting.UI.CustomEmojisMap[alias]; exist { + replaceContent(node, m[0], m[1], createCustomEmoji(alias)) node = node.NextSibling.NextSibling start = 0 continue diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 8c3d2b5395c11..a494c5bd1831b 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -284,7 +284,18 @@ func TestRender_emoji(t *testing.T) { test( ":gitea:", `

:gitea:

`) - + test( + ":custom-emoji:", + `

:custom-emoji:

`) + setting.UI.CustomEmojisMap["custom-emoji"] = ":custom-emoji:" + test( + ":custom-emoji:", + `

:custom-emoji:

`) + test( + "这是字符:1::+1: some🐊 \U0001f44d:custom-emoji: :gitea:", + `

这是字符:1:👍 some🐊 `+ + `👍:custom-emoji: `+ + `:gitea:

`) test( "Some text with 😄 in the middle", `

Some text with 😄 in the middle

`) @@ -414,6 +425,41 @@ func TestRender_ShortLinks(t *testing.T) { `

[[foobar]]

`) } +func TestRender_RelativeImages(t *testing.T) { + setting.AppURL = AppURL + setting.AppSubURL = AppSubURL + tree := util.URLJoin(AppSubURL, "src", "master") + + test := func(input, expected, expectedWiki string) { + buffer, err := markdown.RenderString(&RenderContext{ + URLPrefix: tree, + Metas: localMetas, + }, input) + assert.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + buffer, err = markdown.RenderString(&RenderContext{ + URLPrefix: setting.AppSubURL, + Metas: localMetas, + IsWiki: true, + }, input) + assert.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer)) + } + + rawwiki := util.URLJoin(AppSubURL, "wiki", "raw") + mediatree := util.URLJoin(AppSubURL, "media", "master") + + test( + ``, + ``, + ``) + + test( + ``, + ``, + ``) +} + func Test_ParseClusterFuzz(t *testing.T) { setting.AppURL = AppURL setting.AppSubURL = AppSubURL diff --git a/modules/migrations/base/downloader.go b/modules/migrations/base/downloader.go index 919f4b52a05f1..2388b2dd6e770 100644 --- a/modules/migrations/base/downloader.go +++ b/modules/migrations/base/downloader.go @@ -11,6 +11,13 @@ import ( "code.gitea.io/gitea/modules/structs" ) +// GetCommentOptions represents an options for get comment +type GetCommentOptions struct { + IssueNumber int64 + Page int + PageSize int +} + // Downloader downloads the site repo informations type Downloader interface { SetContext(context.Context) @@ -20,7 +27,8 @@ type Downloader interface { GetReleases() ([]*Release, error) GetLabels() ([]*Label, error) GetIssues(page, perPage int) ([]*Issue, bool, error) - GetComments(issueNumber int64) ([]*Comment, error) + GetComments(opts GetCommentOptions) ([]*Comment, bool, error) + SupportGetRepoComments() bool GetPullRequests(page, perPage int) ([]*PullRequest, bool, error) GetReviews(pullRequestNumber int64) ([]*Review, error) FormatCloneURL(opts MigrateOptions, remoteAddr string) (string, error) diff --git a/modules/migrations/base/null_downloader.go b/modules/migrations/base/null_downloader.go index a93c20339b60d..53a536709d1ff 100644 --- a/modules/migrations/base/null_downloader.go +++ b/modules/migrations/base/null_downloader.go @@ -51,8 +51,8 @@ func (n NullDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) { } // GetComments returns comments according issueNumber -func (n NullDownloader) GetComments(issueNumber int64) ([]*Comment, error) { - return nil, &ErrNotSupported{Entity: "Comments"} +func (n NullDownloader) GetComments(GetCommentOptions) ([]*Comment, bool, error) { + return nil, false, &ErrNotSupported{Entity: "Comments"} } // GetPullRequests returns pull requests according page and perPage @@ -80,3 +80,8 @@ func (n NullDownloader) FormatCloneURL(opts MigrateOptions, remoteAddr string) ( } return remoteAddr, nil } + +// SupportGetRepoComments return true if it supports get repo comments +func (n NullDownloader) SupportGetRepoComments() bool { + return false +} diff --git a/modules/migrations/base/retry_downloader.go b/modules/migrations/base/retry_downloader.go index 82a038b98ba70..e6c80038f1812 100644 --- a/modules/migrations/base/retry_downloader.go +++ b/modules/migrations/base/retry_downloader.go @@ -150,18 +150,19 @@ func (d *RetryDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) { } // GetComments returns a repository's comments with retry -func (d *RetryDownloader) GetComments(issueNumber int64) ([]*Comment, error) { +func (d *RetryDownloader) GetComments(opts GetCommentOptions) ([]*Comment, bool, error) { var ( comments []*Comment + isEnd bool err error ) err = d.retry(func() error { - comments, err = d.Downloader.GetComments(issueNumber) + comments, isEnd, err = d.Downloader.GetComments(opts) return err }) - return comments, err + return comments, isEnd, err } // GetPullRequests returns a repository's pull requests with retry diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go index 40820ae3759ce..665466ffeffdc 100644 --- a/modules/migrations/gitea_downloader.go +++ b/modules/migrations/gitea_downloader.go @@ -435,37 +435,37 @@ func (g *GiteaDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, err } // GetComments returns comments according issueNumber -func (g *GiteaDownloader) GetComments(index int64) ([]*base.Comment, error) { +func (g *GiteaDownloader) GetComments(opts base.GetCommentOptions) ([]*base.Comment, bool, error) { var allComments = make([]*base.Comment, 0, g.maxPerPage) // for i := 1; ; i++ { // make sure gitea can shutdown gracefully select { case <-g.ctx.Done(): - return nil, nil + return nil, false, nil default: } - comments, _, err := g.client.ListIssueComments(g.repoOwner, g.repoName, index, gitea_sdk.ListIssueCommentOptions{ListOptions: gitea_sdk.ListOptions{ + comments, _, err := g.client.ListIssueComments(g.repoOwner, g.repoName, opts.IssueNumber, gitea_sdk.ListIssueCommentOptions{ListOptions: gitea_sdk.ListOptions{ // PageSize: g.maxPerPage, // Page: i, }}) if err != nil { - return nil, fmt.Errorf("error while listing comments for issue #%d. Error: %v", index, err) + return nil, false, fmt.Errorf("error while listing comments for issue #%d. Error: %v", opts.IssueNumber, err) } for _, comment := range comments { reactions, err := g.getCommentReactions(comment.ID) if err != nil { - log.Warn("Unable to load comment reactions during migrating issue #%d for comment %d to %s/%s. Error: %v", index, comment.ID, g.repoOwner, g.repoName, err) + log.Warn("Unable to load comment reactions during migrating issue #%d for comment %d to %s/%s. Error: %v", opts.IssueNumber, comment.ID, g.repoOwner, g.repoName, err) if err2 := models.CreateRepositoryNotice( - fmt.Sprintf("Unable to load reactions during migrating issue #%d for comment %d to %s/%s. Error: %v", index, comment.ID, g.repoOwner, g.repoName, err)); err2 != nil { + fmt.Sprintf("Unable to load reactions during migrating issue #%d for comment %d to %s/%s. Error: %v", opts.IssueNumber, comment.ID, g.repoOwner, g.repoName, err)); err2 != nil { log.Error("create repository notice failed: ", err2) } } allComments = append(allComments, &base.Comment{ - IssueIndex: index, + IssueIndex: opts.IssueNumber, PosterID: comment.Poster.ID, PosterName: comment.Poster.UserName, PosterEmail: comment.Poster.Email, @@ -481,7 +481,7 @@ func (g *GiteaDownloader) GetComments(index int64) ([]*base.Comment, error) { // break // } //} - return allComments, nil + return allComments, true, nil } // GetPullRequests returns pull requests according page and perPage diff --git a/modules/migrations/gitea_downloader_test.go b/modules/migrations/gitea_downloader_test.go index babf038280d7c..f62b19897c63a 100644 --- a/modules/migrations/gitea_downloader_test.go +++ b/modules/migrations/gitea_downloader_test.go @@ -224,7 +224,9 @@ func TestGiteaDownloadRepo(t *testing.T) { Closed: &closed2, }, issues[1]) - comments, err := downloader.GetComments(4) + comments, _, err := downloader.GetComments(base.GetCommentOptions{ + IssueNumber: 4, + }) assert.NoError(t, err) assert.Len(t, comments, 2) assert.EqualValues(t, 1598975370, comments[0].Created.Unix()) diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 8a3f5d34c78d0..9b897662d0304 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -11,6 +11,7 @@ import ( "io" "net/http" "net/url" + "strconv" "strings" "time" @@ -450,8 +451,22 @@ func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, return allIssues, len(issues) < perPage, nil } +// SupportGetRepoComments return true if it supports get repo comments +func (g *GithubDownloaderV3) SupportGetRepoComments() bool { + return true +} + // GetComments returns comments according issueNumber -func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, error) { +func (g *GithubDownloaderV3) GetComments(opts base.GetCommentOptions) ([]*base.Comment, bool, error) { + if opts.IssueNumber > 0 { + comments, err := g.getComments(opts.IssueNumber) + return comments, false, err + } + + return g.GetAllComments(opts.Page, opts.PageSize) +} + +func (g *GithubDownloaderV3) getComments(issueNumber int64) ([]*base.Comment, error) { var ( allComments = make([]*base.Comment, 0, g.maxPerPage) created = "created" @@ -519,6 +534,75 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er return allComments, nil } +// GetAllComments returns repository comments according page and perPageSize +func (g *GithubDownloaderV3) GetAllComments(page, perPage int) ([]*base.Comment, bool, error) { + var ( + allComments = make([]*base.Comment, 0, perPage) + created = "created" + asc = "asc" + ) + opt := &github.IssueListCommentsOptions{ + Sort: &created, + Direction: &asc, + ListOptions: github.ListOptions{ + Page: page, + PerPage: perPage, + }, + } + + g.sleep() + comments, resp, err := g.client.Issues.ListComments(g.ctx, g.repoOwner, g.repoName, 0, opt) + if err != nil { + return nil, false, fmt.Errorf("error while listing repos: %v", err) + } + log.Trace("Request get comments %d/%d, but in fact get %d", perPage, page, len(comments)) + g.rate = &resp.Rate + for _, comment := range comments { + var email string + if comment.User.Email != nil { + email = *comment.User.Email + } + + // get reactions + var reactions []*base.Reaction + for i := 1; ; i++ { + g.sleep() + res, resp, err := g.client.Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{ + Page: i, + PerPage: g.maxPerPage, + }) + if err != nil { + return nil, false, err + } + g.rate = &resp.Rate + if len(res) == 0 { + break + } + for _, reaction := range res { + reactions = append(reactions, &base.Reaction{ + UserID: reaction.User.GetID(), + UserName: reaction.User.GetLogin(), + Content: reaction.GetContent(), + }) + } + } + idx := strings.LastIndex(*comment.IssueURL, "/") + issueIndex, _ := strconv.ParseInt((*comment.IssueURL)[idx+1:], 10, 64) + allComments = append(allComments, &base.Comment{ + IssueIndex: issueIndex, + PosterID: *comment.User.ID, + PosterName: *comment.User.Login, + PosterEmail: email, + Content: *comment.Body, + Created: *comment.CreatedAt, + Updated: *comment.UpdatedAt, + Reactions: reactions, + }) + } + + return allComments, len(allComments) < perPage, nil +} + // GetPullRequests returns pull requests according page and perPage func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) { if perPage > g.maxPerPage { @@ -539,6 +623,7 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq if err != nil { return nil, false, fmt.Errorf("error while listing repos: %v", err) } + log.Trace("Request get pull requests %d/%d, but in fact get %d", perPage, page, len(prs)) g.rate = &resp.Rate for _, pr := range prs { var body string diff --git a/modules/migrations/github_test.go b/modules/migrations/github_test.go index 5bd980a9d8aa5..e0ee2fea84476 100644 --- a/modules/migrations/github_test.go +++ b/modules/migrations/github_test.go @@ -240,7 +240,9 @@ func TestGitHubDownloadRepo(t *testing.T) { }, issues) // downloader.GetComments() - comments, err := downloader.GetComments(2) + comments, _, err := downloader.GetComments(base.GetCommentOptions{ + IssueNumber: 2, + }) assert.NoError(t, err) assert.Len(t, comments, 2) assert.EqualValues(t, []*base.Comment{ diff --git a/modules/migrations/gitlab.go b/modules/migrations/gitlab.go index a697075ff892b..c83989f771fb3 100644 --- a/modules/migrations/gitlab.go +++ b/modules/migrations/gitlab.go @@ -430,7 +430,8 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er // GetComments returns comments according issueNumber // TODO: figure out how to transfer comment reactions -func (g *GitlabDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) { +func (g *GitlabDownloader) GetComments(opts base.GetCommentOptions) ([]*base.Comment, bool, error) { + var issueNumber = opts.IssueNumber var allComments = make([]*base.Comment, 0, g.maxPerPage) var page = 1 @@ -457,7 +458,7 @@ func (g *GitlabDownloader) GetComments(issueNumber int64) ([]*base.Comment, erro } if err != nil { - return nil, fmt.Errorf("error while listing comments: %v %v", g.repoID, err) + return nil, false, fmt.Errorf("error while listing comments: %v %v", g.repoID, err) } for _, comment := range comments { // Flatten comment threads @@ -490,7 +491,7 @@ func (g *GitlabDownloader) GetComments(issueNumber int64) ([]*base.Comment, erro } page = resp.NextPage } - return allComments, nil + return allComments, true, nil } // GetPullRequests returns pull requests according page and perPage diff --git a/modules/migrations/gitlab_test.go b/modules/migrations/gitlab_test.go index 32ed6d807a23b..6a77ff3c230a5 100644 --- a/modules/migrations/gitlab_test.go +++ b/modules/migrations/gitlab_test.go @@ -204,7 +204,9 @@ func TestGitlabDownloadRepo(t *testing.T) { }, }, issues) - comments, err := downloader.GetComments(2) + comments, _, err := downloader.GetComments(base.GetCommentOptions{ + IssueNumber: 2, + }) assert.NoError(t, err) assert.Len(t, comments, 4) assert.EqualValues(t, []*base.Comment{ diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index b616907938ff4..d689b0da1155b 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -227,12 +227,13 @@ func (g *GogsDownloader) getIssues(page int, state string) ([]*base.Issue, bool, } // GetComments returns comments according issueNumber -func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) { +func (g *GogsDownloader) GetComments(opts base.GetCommentOptions) ([]*base.Comment, bool, error) { + var issueNumber = opts.IssueNumber var allComments = make([]*base.Comment, 0, 100) comments, err := g.client.ListIssueComments(g.repoOwner, g.repoName, issueNumber) if err != nil { - return nil, fmt.Errorf("error while listing repos: %v", err) + return nil, false, fmt.Errorf("error while listing repos: %v", err) } for _, comment := range comments { if len(comment.Body) == 0 || comment.Poster == nil { @@ -249,7 +250,7 @@ func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) }) } - return allComments, nil + return allComments, true, nil } // GetTopics return repository topics diff --git a/modules/migrations/gogs_test.go b/modules/migrations/gogs_test.go index d173952b068e6..4e384036d7021 100644 --- a/modules/migrations/gogs_test.go +++ b/modules/migrations/gogs_test.go @@ -103,7 +103,9 @@ func TestGogsDownloadRepo(t *testing.T) { }, issues) // downloader.GetComments() - comments, err := downloader.GetComments(1) + comments, _, err := downloader.GetComments(base.GetCommentOptions{ + IssueNumber: 1, + }) assert.NoError(t, err) assert.Len(t, comments, 1) assert.EqualValues(t, []*base.Comment{ diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 3cdf68ab627da..0a507d9c3341b 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -292,6 +292,8 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts reviewBatchSize = uploader.MaxBatchInsertSize("review") ) + supportAllComments := downloader.SupportGetRepoComments() + if opts.Issues { log.Trace("migrating issues and comments") messenger("repo.migrate.migrating_issues") @@ -311,11 +313,13 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return err } - if opts.Comments { + if opts.Comments && !supportAllComments { var allComments = make([]*base.Comment, 0, commentBatchSize) for _, issue := range issues { log.Trace("migrating issue %d's comments", issue.Number) - comments, err := downloader.GetComments(issue.Number) + comments, _, err := downloader.GetComments(base.GetCommentOptions{ + IssueNumber: issue.Number, + }) if err != nil { if !base.IsErrNotSupported(err) { return err @@ -366,30 +370,34 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts } if opts.Comments { - // plain comments - var allComments = make([]*base.Comment, 0, commentBatchSize) - for _, pr := range prs { - log.Trace("migrating pull request %d's comments", pr.Number) - comments, err := downloader.GetComments(pr.Number) - if err != nil { - if !base.IsErrNotSupported(err) { - return err + if !supportAllComments { + // plain comments + var allComments = make([]*base.Comment, 0, commentBatchSize) + for _, pr := range prs { + log.Trace("migrating pull request %d's comments", pr.Number) + comments, _, err := downloader.GetComments(base.GetCommentOptions{ + IssueNumber: pr.Number, + }) + if err != nil { + if !base.IsErrNotSupported(err) { + return err + } + log.Warn("migrating comments is not supported, ignored") } - log.Warn("migrating comments is not supported, ignored") - } - allComments = append(allComments, comments...) + allComments = append(allComments, comments...) - if len(allComments) >= commentBatchSize { - if err = uploader.CreateComments(allComments[:commentBatchSize]...); err != nil { - return err + if len(allComments) >= commentBatchSize { + if err = uploader.CreateComments(allComments[:commentBatchSize]...); err != nil { + return err + } + allComments = allComments[commentBatchSize:] } - allComments = allComments[commentBatchSize:] } - } - if len(allComments) > 0 { - if err = uploader.CreateComments(allComments...); err != nil { - return err + if len(allComments) > 0 { + if err = uploader.CreateComments(allComments...); err != nil { + return err + } } } @@ -439,6 +447,27 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts } } + if opts.Comments && supportAllComments { + log.Trace("migrating comments") + for i := 1; ; i++ { + comments, isEnd, err := downloader.GetComments(base.GetCommentOptions{ + Page: i, + PageSize: commentBatchSize, + }) + if err != nil { + return err + } + + if err := uploader.CreateComments(comments...); err != nil { + return err + } + + if isEnd { + break + } + } + } + return uploader.Finish() } diff --git a/modules/migrations/restore.go b/modules/migrations/restore.go index 5b44811d52927..6177f80cbbca4 100644 --- a/modules/migrations/restore.go +++ b/modules/migrations/restore.go @@ -212,27 +212,27 @@ func (r *RepositoryRestorer) GetIssues(page, perPage int) ([]*base.Issue, bool, } // GetComments returns comments according issueNumber -func (r *RepositoryRestorer) GetComments(issueNumber int64) ([]*base.Comment, error) { +func (r *RepositoryRestorer) GetComments(opts base.GetCommentOptions) ([]*base.Comment, bool, error) { var comments = make([]*base.Comment, 0, 10) - p := filepath.Join(r.commentDir(), fmt.Sprintf("%d.yml", issueNumber)) + p := filepath.Join(r.commentDir(), fmt.Sprintf("%d.yml", opts.IssueNumber)) _, err := os.Stat(p) if err != nil { if os.IsNotExist(err) { - return nil, nil + return nil, false, nil } - return nil, err + return nil, false, err } bs, err := ioutil.ReadFile(p) if err != nil { - return nil, err + return nil, false, err } err = yaml.Unmarshal(bs, &comments) if err != nil { - return nil, err + return nil, false, err } - return comments, nil + return comments, false, nil } // GetPullRequests returns pull requests according page and perPage diff --git a/modules/notification/webhook/webhook.go b/modules/notification/webhook/webhook.go index 90dc59021c5cc..acdb91efe373e 100644 --- a/modules/notification/webhook/webhook.go +++ b/modules/notification/webhook/webhook.go @@ -562,7 +562,7 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *models.User, issue *m func (m *webhookNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { apiPusher := convert.ToUser(pusher, nil) - apiCommits, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL()) + apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL()) if err != nil { log.Error("commits.ToAPIPayloadCommits failed: %v", err) return @@ -574,6 +574,7 @@ func (m *webhookNotifier) NotifyPushCommits(pusher *models.User, repo *models.Re After: opts.NewCommitID, CompareURL: setting.AppURL + commits.CompareURL, Commits: apiCommits, + HeadCommit: apiHeadCommit, Repo: convert.ToRepo(repo, models.AccessModeOwner), Pusher: apiPusher, Sender: apiPusher, @@ -790,7 +791,7 @@ func (m *webhookNotifier) NotifyDeleteRelease(doer *models.User, rel *models.Rel func (m *webhookNotifier) NotifySyncPushCommits(pusher *models.User, repo *models.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { apiPusher := convert.ToUser(pusher, nil) - apiCommits, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL()) + apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL()) if err != nil { log.Error("commits.ToAPIPayloadCommits failed: %v", err) return @@ -802,6 +803,7 @@ func (m *webhookNotifier) NotifySyncPushCommits(pusher *models.User, repo *model After: opts.NewCommitID, CompareURL: setting.AppURL + commits.CompareURL, Commits: apiCommits, + HeadCommit: apiHeadCommit, Repo: convert.ToRepo(repo, models.AccessModeOwner), Pusher: apiPusher, Sender: apiPusher, diff --git a/modules/references/references.go b/modules/references/references.go index 106e66b47bb5c..ef859abcc79b9 100644 --- a/modules/references/references.go +++ b/modules/references/references.go @@ -5,6 +5,7 @@ package references import ( + "bytes" "net/url" "regexp" "strconv" @@ -14,6 +15,8 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/mdstripper" "code.gitea.io/gitea/modules/setting" + + "github.com/yuin/goldmark/util" ) var ( @@ -321,7 +324,7 @@ func FindRenderizableReferenceNumeric(content string, prOnly bool) (bool, *Rende return false, nil } } - r := getCrossReference([]byte(content), match[2], match[3], false, prOnly) + r := getCrossReference(util.StringToReadOnlyBytes(content), match[2], match[3], false, prOnly) if r == nil { return false, nil } @@ -465,18 +468,17 @@ func findAllIssueReferencesBytes(content []byte, links []string) []*rawReference } func getCrossReference(content []byte, start, end int, fromLink bool, prOnly bool) *rawReference { - refid := string(content[start:end]) - sep := strings.IndexAny(refid, "#!") + sep := bytes.IndexAny(content[start:end], "#!") if sep < 0 { return nil } - isPull := refid[sep] == '!' + isPull := content[start+sep] == '!' if prOnly && !isPull { return nil } - repo := refid[:sep] - issue := refid[sep+1:] - index, err := strconv.ParseInt(issue, 10, 64) + repo := string(content[start : start+sep]) + issue := string(content[start+sep+1 : end]) + index, err := strconv.ParseInt(string(issue), 10, 64) if err != nil { return nil } diff --git a/modules/repository/commits.go b/modules/repository/commits.go index 6b67c2c262428..eaaf3b8b198b0 100644 --- a/modules/repository/commits.go +++ b/modules/repository/commits.go @@ -28,8 +28,8 @@ type PushCommit struct { // PushCommits represents list of commits in a push operation. type PushCommits struct { - Len int Commits []*PushCommit + HeadCommit *PushCommit CompareURL string avatars map[string]string @@ -44,67 +44,88 @@ func NewPushCommits() *PushCommits { } } -// ToAPIPayloadCommits converts a PushCommits object to -// api.PayloadCommit format. -func (pc *PushCommits) ToAPIPayloadCommits(repoPath, repoLink string) ([]*api.PayloadCommit, error) { - commits := make([]*api.PayloadCommit, len(pc.Commits)) - - if pc.emailUsers == nil { - pc.emailUsers = make(map[string]*models.User) - } +// toAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object. +func (pc *PushCommits) toAPIPayloadCommit(repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) { var err error - for i, commit := range pc.Commits { - authorUsername := "" - author, ok := pc.emailUsers[commit.AuthorEmail] - if !ok { - author, err = models.GetUserByEmail(commit.AuthorEmail) - if err == nil { - authorUsername = author.Name - pc.emailUsers[commit.AuthorEmail] = author - } - } else { + authorUsername := "" + author, ok := pc.emailUsers[commit.AuthorEmail] + if !ok { + author, err = models.GetUserByEmail(commit.AuthorEmail) + if err == nil { authorUsername = author.Name + pc.emailUsers[commit.AuthorEmail] = author } + } else { + authorUsername = author.Name + } - committerUsername := "" - committer, ok := pc.emailUsers[commit.CommitterEmail] - if !ok { - committer, err = models.GetUserByEmail(commit.CommitterEmail) - if err == nil { - // TODO: check errors other than email not found. - committerUsername = committer.Name - pc.emailUsers[commit.CommitterEmail] = committer - } - } else { + committerUsername := "" + committer, ok := pc.emailUsers[commit.CommitterEmail] + if !ok { + committer, err = models.GetUserByEmail(commit.CommitterEmail) + if err == nil { + // TODO: check errors other than email not found. committerUsername = committer.Name + pc.emailUsers[commit.CommitterEmail] = committer } + } else { + committerUsername = committer.Name + } - fileStatus, err := git.GetCommitFileStatus(repoPath, commit.Sha1) + fileStatus, err := git.GetCommitFileStatus(repoPath, commit.Sha1) + if err != nil { + return nil, fmt.Errorf("FileStatus [commit_sha1: %s]: %v", commit.Sha1, err) + } + + return &api.PayloadCommit{ + ID: commit.Sha1, + Message: commit.Message, + URL: fmt.Sprintf("%s/commit/%s", repoLink, commit.Sha1), + Author: &api.PayloadUser{ + Name: commit.AuthorName, + Email: commit.AuthorEmail, + UserName: authorUsername, + }, + Committer: &api.PayloadUser{ + Name: commit.CommitterName, + Email: commit.CommitterEmail, + UserName: committerUsername, + }, + Added: fileStatus.Added, + Removed: fileStatus.Removed, + Modified: fileStatus.Modified, + Timestamp: commit.Timestamp, + }, nil +} + +// ToAPIPayloadCommits converts a PushCommits object to api.PayloadCommit format. +// It returns all converted commits and, if provided, the head commit or an error otherwise. +func (pc *PushCommits) ToAPIPayloadCommits(repoPath, repoLink string) ([]*api.PayloadCommit, *api.PayloadCommit, error) { + commits := make([]*api.PayloadCommit, len(pc.Commits)) + var headCommit *api.PayloadCommit + + if pc.emailUsers == nil { + pc.emailUsers = make(map[string]*models.User) + } + for i, commit := range pc.Commits { + apiCommit, err := pc.toAPIPayloadCommit(repoPath, repoLink, commit) if err != nil { - return nil, fmt.Errorf("FileStatus [commit_sha1: %s]: %v", commit.Sha1, err) + return nil, nil, err } - commits[i] = &api.PayloadCommit{ - ID: commit.Sha1, - Message: commit.Message, - URL: fmt.Sprintf("%s/commit/%s", repoLink, commit.Sha1), - Author: &api.PayloadUser{ - Name: commit.AuthorName, - Email: commit.AuthorEmail, - UserName: authorUsername, - }, - Committer: &api.PayloadUser{ - Name: commit.CommitterName, - Email: commit.CommitterEmail, - UserName: committerUsername, - }, - Added: fileStatus.Added, - Removed: fileStatus.Removed, - Modified: fileStatus.Modified, - Timestamp: commit.Timestamp, + commits[i] = apiCommit + if pc.HeadCommit != nil && pc.HeadCommit.Sha1 == commits[i].ID { + headCommit = apiCommit } } - return commits, nil + if pc.HeadCommit != nil && headCommit == nil { + var err error + headCommit, err = pc.toAPIPayloadCommit(repoPath, repoLink, pc.HeadCommit) + if err != nil { + return nil, nil, err + } + } + return commits, headCommit, nil } // AvatarLink tries to match user in database with e-mail @@ -157,13 +178,9 @@ func CommitToPushCommit(commit *git.Commit) *PushCommit { // ListToPushCommits transforms a list.List to PushCommits type. func ListToPushCommits(l *list.List) *PushCommits { var commits []*PushCommit - var actEmail string for e := l.Front(); e != nil; e = e.Next() { - commit := e.Value.(*git.Commit) - if actEmail == "" { - actEmail = commit.Committer.Email - } - commits = append(commits, CommitToPushCommit(commit)) + commit := CommitToPushCommit(e.Value.(*git.Commit)) + commits = append(commits, commit) } - return &PushCommits{l.Len(), commits, "", make(map[string]string), make(map[string]*models.User)} + return &PushCommits{commits, nil, "", make(map[string]string), make(map[string]*models.User)} } diff --git a/modules/repository/commits_test.go b/modules/repository/commits_test.go index a5b28ce933ed0..8e0d8bf90fa02 100644 --- a/modules/repository/commits_test.go +++ b/modules/repository/commits_test.go @@ -46,12 +46,13 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) { Message: "good signed commit", }, } - pushCommits.Len = len(pushCommits.Commits) + pushCommits.HeadCommit = &PushCommit{Sha1: "69554a6"} repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 16}).(*models.Repository) - payloadCommits, err := pushCommits.ToAPIPayloadCommits(repo.RepoPath(), "/user2/repo16") + payloadCommits, headCommit, err := pushCommits.ToAPIPayloadCommits(repo.RepoPath(), "/user2/repo16") assert.NoError(t, err) assert.Len(t, payloadCommits, 3) + assert.NotNil(t, headCommit) assert.Equal(t, "69554a6", payloadCommits[0].ID) assert.Equal(t, "not signed commit", payloadCommits[0].Message) @@ -85,6 +86,17 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) { assert.EqualValues(t, []string{"readme.md"}, payloadCommits[2].Added) assert.EqualValues(t, []string{}, payloadCommits[2].Removed) assert.EqualValues(t, []string{}, payloadCommits[2].Modified) + + assert.Equal(t, "69554a6", headCommit.ID) + assert.Equal(t, "not signed commit", headCommit.Message) + assert.Equal(t, "/user2/repo16/commit/69554a6", headCommit.URL) + assert.Equal(t, "User2", headCommit.Committer.Name) + assert.Equal(t, "user2", headCommit.Committer.UserName) + assert.Equal(t, "User2", headCommit.Author.Name) + assert.Equal(t, "user2", headCommit.Author.UserName) + assert.EqualValues(t, []string{}, headCommit.Added) + assert.EqualValues(t, []string{}, headCommit.Removed) + assert.EqualValues(t, []string{"readme.md"}, headCommit.Modified) } func TestPushCommits_AvatarLink(t *testing.T) { @@ -109,7 +121,6 @@ func TestPushCommits_AvatarLink(t *testing.T) { Message: "message2", }, } - pushCommits.Len = len(pushCommits.Commits) assert.Equal(t, "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon&s=112", @@ -177,7 +188,6 @@ func TestListToPushCommits(t *testing.T) { }) pushCommits := ListToPushCommits(l) - assert.Equal(t, 2, pushCommits.Len) if assert.Len(t, pushCommits.Commits, 2) { assert.Equal(t, "Message1", pushCommits.Commits[0].Message) assert.Equal(t, hexString1, pushCommits.Commits[0].Sha1) diff --git a/modules/setting/git.go b/modules/setting/git.go index 308d94894ba72..aa838a8d641a7 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -7,7 +7,6 @@ package setting import ( "time" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" ) @@ -19,13 +18,14 @@ var ( MaxGitDiffLines int MaxGitDiffLineCharacters int MaxGitDiffFiles int - CommitsRangeSize int - BranchesRangeSize int + CommitsRangeSize int // CommitsRangeSize the default commits range size + BranchesRangeSize int // BranchesRangeSize the default branches range size VerbosePush bool VerbosePushDelay time.Duration GCArgs []string `ini:"GC_ARGS" delim:" "` EnableAutoGitWireProtocol bool PullRequestPushMessage bool + LargeObjectThreshold int64 Timeout struct { Default int Migrate int @@ -46,6 +46,7 @@ var ( GCArgs: []string{}, EnableAutoGitWireProtocol: true, PullRequestPushMessage: true, + LargeObjectThreshold: 1024 * 1024, Timeout: struct { Default int Migrate int @@ -54,7 +55,7 @@ var ( Pull int GC int `ini:"GC"` }{ - Default: int(git.DefaultCommandExecutionTimeout / time.Second), + Default: 360, Migrate: 600, Mirror: 300, Clone: 300, @@ -68,35 +69,4 @@ func newGit() { if err := Cfg.Section("git").MapTo(&Git); err != nil { log.Fatal("Failed to map Git settings: %v", err) } - if err := git.SetExecutablePath(Git.Path); err != nil { - log.Fatal("Failed to initialize Git settings: %v", err) - } - git.DefaultCommandExecutionTimeout = time.Duration(Git.Timeout.Default) * time.Second - - version, err := git.LocalVersion() - if err != nil { - log.Fatal("Error retrieving git version: %v", err) - } - - // force cleanup args - git.GlobalCommandArgs = []string{} - - if git.CheckGitVersionAtLeast("2.9") == nil { - // Explicitly disable credential helper, otherwise Git credentials might leak - git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "credential.helper=") - } - - var format = "Git Version: %s" - var args = []interface{}{version.Original()} - // Since git wire protocol has been released from git v2.18 - if Git.EnableAutoGitWireProtocol && git.CheckGitVersionAtLeast("2.18") == nil { - git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "protocol.version=2") - format += ", Wire Protocol %s Enabled" - args = append(args, "Version 2") // for focus color - } - - git.CommitsRangeSize = Git.CommitsRangeSize - git.BranchesRangeSize = Git.BranchesRangeSize - - log.Info(format, args...) } diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go index 8b9224b86a6cb..a4bbd3c3ff37b 100644 --- a/modules/setting/lfs.go +++ b/modules/setting/lfs.go @@ -9,7 +9,6 @@ import ( "time" "code.gitea.io/gitea/modules/generate" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" ini "gopkg.in/ini.v1" @@ -67,24 +66,3 @@ func newLFSService() { } } } - -// CheckLFSVersion will check lfs version, if not satisfied, then disable it. -func CheckLFSVersion() { - if LFS.StartServer { - //Disable LFS client hooks if installed for the current OS user - //Needs at least git v2.1.2 - - err := git.LoadGitVersion() - if err != nil { - log.Fatal("Error retrieving git version: %v", err) - } - - if git.CheckGitVersionAtLeast("2.1.2") != nil { - LFS.StartServer = false - log.Error("LFS server support needs at least Git v2.1.2") - } else { - git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "filter.lfs.required=", - "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") - } - } -} diff --git a/modules/setting/service.go b/modules/setting/service.go index 17cc8764a57aa..a391926382c4c 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -6,6 +6,7 @@ package setting import ( "regexp" + "strings" "time" "code.gitea.io/gitea/modules/log" @@ -13,7 +14,11 @@ import ( ) // Service settings -var Service struct { +var Service = struct { + DefaultUserVisibility string + DefaultUserVisibilityMode structs.VisibleType + AllowedUserVisibilityModes []string + AllowedUserVisibilityModesSlice AllowedVisibility `ini:"-"` DefaultOrgVisibility string DefaultOrgVisibilityMode structs.VisibleType ActiveCodeLives int @@ -56,6 +61,7 @@ var Service struct { AutoWatchOnChanges bool DefaultOrgMemberVisible bool UserDeleteWithCommentsMaxTime time.Duration + ValidSiteURLSchemes []string // OpenID settings EnableOpenIDSignIn bool @@ -68,6 +74,29 @@ var Service struct { RequireSigninView bool `ini:"REQUIRE_SIGNIN_VIEW"` DisableUsersPage bool `ini:"DISABLE_USERS_PAGE"` } `ini:"service.explore"` +}{ + AllowedUserVisibilityModesSlice: []bool{true, true, true}, +} + +// AllowedVisibility store in a 3 item bool array what is allowed +type AllowedVisibility []bool + +// IsAllowedVisibility check if a AllowedVisibility allow a specific VisibleType +func (a AllowedVisibility) IsAllowedVisibility(t structs.VisibleType) bool { + if int(t) >= len(a) { + return false + } + return a[t] +} + +// ToVisibleTypeSlice convert a AllowedVisibility into a VisibleType slice +func (a AllowedVisibility) ToVisibleTypeSlice() (result []structs.VisibleType) { + for i, v := range a { + if v { + result = append(result, structs.VisibleType(i)) + } + } + return } func newService() { @@ -118,10 +147,29 @@ func newService() { Service.EnableUserHeatmap = sec.Key("ENABLE_USER_HEATMAP").MustBool(true) Service.AutoWatchNewRepos = sec.Key("AUTO_WATCH_NEW_REPOS").MustBool(true) Service.AutoWatchOnChanges = sec.Key("AUTO_WATCH_ON_CHANGES").MustBool(false) + Service.DefaultUserVisibility = sec.Key("DEFAULT_USER_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes)) + Service.DefaultUserVisibilityMode = structs.VisibilityModes[Service.DefaultUserVisibility] + Service.AllowedUserVisibilityModes = sec.Key("ALLOWED_USER_VISIBILITY_MODES").Strings(",") + if len(Service.AllowedUserVisibilityModes) != 0 { + Service.AllowedUserVisibilityModesSlice = []bool{false, false, false} + for _, sMode := range Service.AllowedUserVisibilityModes { + Service.AllowedUserVisibilityModesSlice[structs.VisibilityModes[sMode]] = true + } + } Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes)) Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility] Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool() Service.UserDeleteWithCommentsMaxTime = sec.Key("USER_DELETE_WITH_COMMENTS_MAX_TIME").MustDuration(0) + sec.Key("VALID_SITE_URL_SCHEMES").MustString("http,https") + Service.ValidSiteURLSchemes = sec.Key("VALID_SITE_URL_SCHEMES").Strings(",") + schemes := make([]string, len(Service.ValidSiteURLSchemes)) + for _, scheme := range Service.ValidSiteURLSchemes { + scheme = strings.ToLower(strings.TrimSpace(scheme)) + if scheme != "" { + schemes = append(schemes, scheme) + } + } + Service.ValidSiteURLSchemes = schemes if err := Cfg.Section("service.explore").MapTo(&Service.Explore); err != nil { log.Fatal("Failed to map service.explore settings: %v", err) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 020101430d30d..e3da5796e4268 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -208,7 +208,9 @@ var ( DefaultTheme string Themes []string Reactions []string - ReactionsMap map[string]bool + ReactionsMap map[string]bool `ini:"-"` + CustomEmojis []string + CustomEmojisMap map[string]string `ini:"-"` SearchRepoDescription bool UseServiceWorker bool @@ -256,6 +258,8 @@ var ( DefaultTheme: `gitea`, Themes: []string{`gitea`, `arc-green`}, Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, + CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`}, + CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"}, Notification: struct { MinTimeout time.Duration TimeoutStep time.Duration @@ -469,7 +473,8 @@ func getWorkPath(appPath string) string { func init() { IsWindows = runtime.GOOS == "windows" // We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically - log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "trace", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout)) + // By default set this logger at Info - we'll change it later but we need to start with something. + log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "info", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout)) var err error if AppPath, err = getAppPath(); err != nil { @@ -982,6 +987,10 @@ func NewContext() { for _, reaction := range UI.Reactions { UI.ReactionsMap[reaction] = true } + UI.CustomEmojisMap = make(map[string]string) + for _, emoji := range UI.CustomEmojis { + UI.CustomEmojisMap[emoji] = ":" + emoji + ":" + } } func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) { @@ -1158,6 +1167,19 @@ func CreateOrAppendToCustomConf(callback func(cfg *ini.File)) { if err := cfg.SaveTo(CustomConf); err != nil { log.Fatal("error saving to custom config: %v", err) } + + // Change permissions to be more restrictive + fi, err := os.Stat(CustomConf) + if err != nil { + log.Error("Failed to determine current conf file permissions: %v", err) + return + } + + if fi.Mode().Perm() > 0o600 { + if err = os.Chmod(CustomConf, 0o600); err != nil { + log.Warn("Failed changing conf file permissions to -rw-------. Consider changing them manually.") + } + } } // NewServices initializes the services diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 22683b003be10..c0897377c56fd 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -12,6 +12,7 @@ import ( "encoding/pem" "fmt" "io" + "net" "os" "os/exec" "path/filepath" @@ -65,7 +66,7 @@ func sessionHandler(session ssh.Session) { args := []string{"serv", "key-" + keyID, "--config=" + setting.CustomConf} log.Trace("SSH: Arguments: %v", args) - cmd := exec.Command(setting.AppPath, args...) + cmd := exec.CommandContext(session.Context(), setting.AppPath, args...) cmd.Env = append( os.Environ(), "SSH_ORIGINAL_COMMAND="+command, @@ -239,6 +240,15 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { return true } +// sshConnectionFailed logs a failed connection +// - this mainly exists to give a nice function name in logging +func sshConnectionFailed(conn net.Conn, err error) { + // Log the underlying error with a specific message + log.Warn("Failed connection from %s with error: %v", conn.RemoteAddr(), err) + // Log with the standard failed authentication from message for simpler fail2ban configuration + log.Warn("Failed authentication attempt from %s", conn.RemoteAddr()) +} + // Listen starts a SSH server listens on given port. func Listen(host string, port int, ciphers []string, keyExchanges []string, macs []string) { srv := ssh.Server{ @@ -252,6 +262,7 @@ func Listen(host string, port int, ciphers []string, keyExchanges []string, macs config.Ciphers = ciphers return config }, + ConnectionFailedCallback: sshConnectionFailed, // We need to explicitly disable the PtyCallback so text displays // properly. PtyCallback: func(ctx ssh.Context, pty ssh.Pty) bool { diff --git a/modules/structs/admin_user.go b/modules/structs/admin_user.go index 5da4e9608bea7..facf16a39552a 100644 --- a/modules/structs/admin_user.go +++ b/modules/structs/admin_user.go @@ -19,6 +19,7 @@ type CreateUserOption struct { Password string `json:"password" binding:"Required;MaxSize(255)"` MustChangePassword *bool `json:"must_change_password"` SendNotify bool `json:"send_notify"` + Visibility string `json:"visibility" binding:"In(,public,limited,private)"` } // EditUserOption edit user options @@ -43,4 +44,5 @@ type EditUserOption struct { ProhibitLogin *bool `json:"prohibit_login"` AllowCreateOrganization *bool `json:"allow_create_organization"` Restricted *bool `json:"restricted"` + Visibility string `json:"visibility" binding:"In(,public,limited,private)"` } diff --git a/modules/structs/hook.go b/modules/structs/hook.go index 693820b57d3e9..e4ec99df40d77 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -62,7 +62,6 @@ type EditHookOption struct { // Payloader payload is some part of one hook type Payloader interface { - SetSecret(string) JSONPayload() ([]byte, error) } @@ -124,7 +123,6 @@ var ( // CreatePayload FIXME type CreatePayload struct { - Secret string `json:"secret"` Sha string `json:"sha"` Ref string `json:"ref"` RefType string `json:"ref_type"` @@ -132,11 +130,6 @@ type CreatePayload struct { Sender *User `json:"sender"` } -// SetSecret modifies the secret of the CreatePayload -func (p *CreatePayload) SetSecret(secret string) { - p.Secret = secret -} - // JSONPayload return payload information func (p *CreatePayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary @@ -181,7 +174,6 @@ const ( // DeletePayload represents delete payload type DeletePayload struct { - Secret string `json:"secret"` Ref string `json:"ref"` RefType string `json:"ref_type"` PusherType PusherType `json:"pusher_type"` @@ -189,11 +181,6 @@ type DeletePayload struct { Sender *User `json:"sender"` } -// SetSecret modifies the secret of the DeletePayload -func (p *DeletePayload) SetSecret(secret string) { - p.Secret = secret -} - // JSONPayload implements Payload func (p *DeletePayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary @@ -209,17 +196,11 @@ func (p *DeletePayload) JSONPayload() ([]byte, error) { // ForkPayload represents fork payload type ForkPayload struct { - Secret string `json:"secret"` Forkee *Repository `json:"forkee"` Repo *Repository `json:"repository"` Sender *User `json:"sender"` } -// SetSecret modifies the secret of the ForkPayload -func (p *ForkPayload) SetSecret(secret string) { - p.Secret = secret -} - // JSONPayload implements Payload func (p *ForkPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary @@ -238,7 +219,6 @@ const ( // IssueCommentPayload represents a payload information of issue comment event. type IssueCommentPayload struct { - Secret string `json:"secret"` Action HookIssueCommentAction `json:"action"` Issue *Issue `json:"issue"` Comment *Comment `json:"comment"` @@ -248,11 +228,6 @@ type IssueCommentPayload struct { IsPull bool `json:"is_pull"` } -// SetSecret modifies the secret of the IssueCommentPayload -func (p *IssueCommentPayload) SetSecret(secret string) { - p.Secret = secret -} - // JSONPayload implements Payload func (p *IssueCommentPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary @@ -278,18 +253,12 @@ const ( // ReleasePayload represents a payload information of release event. type ReleasePayload struct { - Secret string `json:"secret"` Action HookReleaseAction `json:"action"` Release *Release `json:"release"` Repository *Repository `json:"repository"` Sender *User `json:"sender"` } -// SetSecret modifies the secret of the ReleasePayload -func (p *ReleasePayload) SetSecret(secret string) { - p.Secret = secret -} - // JSONPayload implements Payload func (p *ReleasePayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary @@ -305,7 +274,6 @@ func (p *ReleasePayload) JSONPayload() ([]byte, error) { // PushPayload represents a payload information of push event. type PushPayload struct { - Secret string `json:"secret"` Ref string `json:"ref"` Before string `json:"before"` After string `json:"after"` @@ -317,11 +285,6 @@ type PushPayload struct { Sender *User `json:"sender"` } -// SetSecret modifies the secret of the PushPayload -func (p *PushPayload) SetSecret(secret string) { - p.Secret = secret -} - // JSONPayload FIXME func (p *PushPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary @@ -389,7 +352,6 @@ const ( // IssuePayload represents the payload information that is sent along with an issue event. type IssuePayload struct { - Secret string `json:"secret"` Action HookIssueAction `json:"action"` Index int64 `json:"number"` Changes *ChangesPayload `json:"changes,omitempty"` @@ -398,11 +360,6 @@ type IssuePayload struct { Sender *User `json:"sender"` } -// SetSecret modifies the secret of the IssuePayload. -func (p *IssuePayload) SetSecret(secret string) { - p.Secret = secret -} - // JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces. func (p *IssuePayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary @@ -430,7 +387,6 @@ type ChangesPayload struct { // PullRequestPayload represents a payload information of pull request event. type PullRequestPayload struct { - Secret string `json:"secret"` Action HookIssueAction `json:"action"` Index int64 `json:"number"` Changes *ChangesPayload `json:"changes,omitempty"` @@ -440,11 +396,6 @@ type PullRequestPayload struct { Review *ReviewPayload `json:"review"` } -// SetSecret modifies the secret of the PullRequestPayload. -func (p *PullRequestPayload) SetSecret(secret string) { - p.Secret = secret -} - // JSONPayload FIXME func (p *PullRequestPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary @@ -476,18 +427,12 @@ const ( // RepositoryPayload payload for repository webhooks type RepositoryPayload struct { - Secret string `json:"secret"` Action HookRepoAction `json:"action"` Repository *Repository `json:"repository"` Organization *User `json:"organization"` Sender *User `json:"sender"` } -// SetSecret modifies the secret of the RepositoryPayload -func (p *RepositoryPayload) SetSecret(secret string) { - p.Secret = secret -} - // JSONPayload JSON representation of the payload func (p *RepositoryPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary diff --git a/modules/structs/notifications.go b/modules/structs/notifications.go index 8daa6de1686f5..675dcf76b127e 100644 --- a/modules/structs/notifications.go +++ b/modules/structs/notifications.go @@ -21,14 +21,28 @@ type NotificationThread struct { // NotificationSubject contains the notification subject (Issue/Pull/Commit) type NotificationSubject struct { - Title string `json:"title"` - URL string `json:"url"` - LatestCommentURL string `json:"latest_comment_url"` - Type string `json:"type" binding:"In(Issue,Pull,Commit)"` - State StateType `json:"state"` + Title string `json:"title"` + URL string `json:"url"` + LatestCommentURL string `json:"latest_comment_url"` + Type NotifySubjectType `json:"type" binding:"In(Issue,Pull,Commit)"` + State StateType `json:"state"` } // NotificationCount number of unread notifications type NotificationCount struct { New int64 `json:"new"` } + +// NotifySubjectType represent type of notification subject +type NotifySubjectType string + +const ( + // NotifySubjectIssue an issue is subject of an notification + NotifySubjectIssue NotifySubjectType = "Issue" + // NotifySubjectPull an pull is subject of an notification + NotifySubjectPull NotifySubjectType = "Pull" + // NotifySubjectCommit an commit is subject of an notification + NotifySubjectCommit NotifySubjectType = "Commit" + // NotifySubjectRepository an repository is subject of an notification + NotifySubjectRepository NotifySubjectType = "Repository" +) diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 4fdc1e54cb282..cef864c0205bf 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -180,6 +180,36 @@ type EditRepoOption struct { MirrorInterval *string `json:"mirror_interval,omitempty"` } +// GenerateRepoOption options when creating repository using a template +// swagger:model +type GenerateRepoOption struct { + // The organization or person who will own the new repository + // + // required: true + Owner string `json:"owner"` + // Name of the repository to create + // + // required: true + // unique: true + Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"` + // Description of the repository to create + Description string `json:"description" binding:"MaxSize(255)"` + // Whether the repository is private + Private bool `json:"private"` + // include git content of default branch in template repo + GitContent bool `json:"git_content"` + // include topics in template repo + Topics bool `json:"topics"` + // include git hooks in template repo + GitHooks bool `json:"git_hooks"` + // include webhooks in template repo + Webhooks bool `json:"webhooks"` + // include avatar of the template repo + Avatar bool `json:"avatar"` + // include labels in template repo + Labels bool `json:"labels"` +} + // CreateBranchRepoOption options when creating a branch in a repository // swagger:model type CreateBranchRepoOption struct { diff --git a/modules/structs/settings.go b/modules/structs/settings.go index 842b12792d1d9..90c4a2107bbdf 100644 --- a/modules/structs/settings.go +++ b/modules/structs/settings.go @@ -18,6 +18,7 @@ type GeneralRepoSettings struct { type GeneralUISettings struct { DefaultTheme string `json:"default_theme"` AllowedReactions []string `json:"allowed_reactions"` + CustomEmojis []string `json:"custom_emojis"` } // GeneralAPISettings contains global api settings exposed by it diff --git a/modules/structs/user.go b/modules/structs/user.go index 0d8b0300c30f6..a3c8f0c32a7b3 100644 --- a/modules/structs/user.go +++ b/modules/structs/user.go @@ -43,6 +43,8 @@ type User struct { Website string `json:"website"` // the user's description Description string `json:"description"` + // User visibility level option: public, limited, private + Visibility string `json:"visibility"` // user counts Followers int `json:"followers_count"` diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 83359a6ef234b..f9b2dafd22a14 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -90,6 +90,9 @@ func NewFuncMap() []template.FuncMap { "AllowedReactions": func() []string { return setting.UI.Reactions }, + "CustomEmojis": func() map[string]string { + return setting.UI.CustomEmojisMap + }, "Safe": Safe, "SafeJS": SafeJS, "JSEscape": JSEscape, diff --git a/modules/validation/binding.go b/modules/validation/binding.go index 4cef48daf32d6..5d5c64611f29a 100644 --- a/modules/validation/binding.go +++ b/modules/validation/binding.go @@ -55,6 +55,7 @@ func CheckGitRefAdditionalRulesValid(name string) bool { func AddBindingRules() { addGitRefNameBindingRule() addValidURLBindingRule() + addValidSiteURLBindingRule() addGlobPatternRule() addRegexPatternRule() addGlobOrRegexPatternRule() @@ -102,6 +103,24 @@ func addValidURLBindingRule() { }) } +func addValidSiteURLBindingRule() { + // URL validation rule + binding.AddRule(&binding.Rule{ + IsMatch: func(rule string) bool { + return strings.HasPrefix(rule, "ValidSiteUrl") + }, + IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) { + str := fmt.Sprintf("%v", val) + if len(str) != 0 && !IsValidSiteURL(str) { + errs.Add([]string{name}, binding.ERR_URL, "Url") + return false, errs + } + + return true, errs + }, + }) +} + func addGlobPatternRule() { binding.AddRule(&binding.Rule{ IsMatch: func(rule string) bool { diff --git a/modules/validation/helpers.go b/modules/validation/helpers.go index c22e667a2ebf9..343261aac5b59 100644 --- a/modules/validation/helpers.go +++ b/modules/validation/helpers.go @@ -52,6 +52,25 @@ func IsValidURL(uri string) bool { return true } +// IsValidSiteURL checks if URL is valid +func IsValidSiteURL(uri string) bool { + u, err := url.ParseRequestURI(uri) + if err != nil { + return false + } + + if !validPort(portOnly(u.Host)) { + return false + } + + for _, scheme := range setting.Service.ValidSiteURLSchemes { + if scheme == u.Scheme { + return true + } + } + return false +} + // IsAPIURL checks if URL is current Gitea instance API URL func IsAPIURL(uri string) bool { return strings.HasPrefix(strings.ToLower(uri), strings.ToLower(setting.AppURL+"api")) diff --git a/options/license/CC-BY-2.5-AU b/options/license/CC-BY-2.5-AU new file mode 100644 index 0000000000000..23b8800919036 --- /dev/null +++ b/options/license/CC-BY-2.5-AU @@ -0,0 +1,112 @@ +Creative Commons Attribution 2.5 Australia + +CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENCE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. + +Licence + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENCE ("CCPL" OR "LICENCE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORISED UNDER THIS LICENCE AND/OR APPLICABLE LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENCE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + + 1. Definitions + + a. "Collective Work" means a work, such as a periodical issue, anthology or encyclopaedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this Licence. + + b. "Derivative Work" means a work that reproduces a substantial part of the Work, or of the Work and other pre-existing works protected by copyright, or that is an adaptation of a Work that is a literary, dramatic, musical or artistic work. Derivative Works include a translation, musical arrangement, dramatisation, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which a work may be adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this Licence. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this Licence. + + c. "Licensor" means the individual or entity that offers the Work under the terms of this Licence. + + d. "Moral rights law" means laws under which an individual who creates a work protected by copyright has rights of integrity of authorship of the work, rights of attribution of authorship of the work, rights not to have authorship of the work falsely attributed, or rights of a similar or analogous nature in the work anywhere in the world. + + e. "Original Author" means the individual or entity who created the Work. + + f. "Work" means the work or other subject-matter protected by copyright that is offered under the terms of this Licence, which may include (without limitation) a literary, dramatic, musical or artistic work, a sound recording or cinematograph film, a published edition of a literary, dramatic, musical or artistic work or a television or sound broadcast. + + g. "You" means an individual or entity exercising rights under this Licence who has not previously violated the terms of this Licence with respect to the Work, or who has received express permission from the Licensor to exercise rights under this Licence despite a previous violation. + + h. "Licence Elements" means the following high-level licence attributes as selected by Licensor and indicated in the title of this Licence: Attribution, NonCommercial, NoDerivatives, ShareAlike. + +2. Fair Dealing and Other Rights. Nothing in this Licence excludes or modifies, or is intended to exclude or modify, (including by reducing, limiting, or restricting) the rights of You or others to use the Work arising from fair dealings or other limitations on the rights of the copyright owner or the Original Author under copyright law, moral rights law or other applicable laws. + +3. Licence Grant. Subject to the terms and conditions of this Licence, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) licence to exercise the rights in the Work as stated below: + + a. to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works; + + b. to create and reproduce Derivative Works; + + c. to publish, communicate to the public, distribute copies or records of, exhibit or display publicly, perform publicly and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works; + + d. to publish, communicate to the public, distribute copies or records of, exhibit or display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works; + + e. For the avoidance of doubt, where the Work is a musical composition: + + i. Performance Royalties Under Blanket Licences. Licensor will not collect, whether individually or via a performance rights society, royalties for Your communication to the public, broadcast, public performance or public digital performance (e.g. webcast) of the Work. + + ii. Mechanical Rights and Statutory Royalties. Licensor will not collect, whether individually or via a music rights agency, designated agent or a music publisher, royalties for any record You create from the Work ("cover version") and distribute, subject to the compulsory licence created by 17 USC Section 115 of the US Copyright Act (or an equivalent statutory licence under the Australian Copyright Act or in other jurisdictions). + + + f. Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor will not collect, whether individually or via a performance-rights society, royalties for Your public digital performance (e.g. webcast) of the Work, subject to the compulsory licence created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions). + +The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor under this Licence are hereby reserved. + +4. Restrictions. The licence granted in Section 3 above is expressly made subject to and limited by the following restrictions: + + a. You may publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work only under the terms of this Licence, and You must include a copy of, or the Uniform Resource Identifier for, this Licence with every copy or record of the Work You publish, communicate to the public, distribute, publicly exhibit or display, publicly perform or publicly digitally perform. You may not offer or impose any terms on the Work that exclude, alter or restrict the terms of this Licence or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this Licence and to the disclaimer of representations and warranties. You may not publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this Licence. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this Licence. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by Section 4(b), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by Section 4(b), as requested. + + b. If you publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work. You must also give clear and reasonably prominent credit to (i) the Original Author (by name or pseudonym if applicable), if the name or pseudonym is supplied; and (ii) if another party or parties (eg a sponsor institute, publishing entity or journal) is designated for attribution in the copyright notice, terms of service or other reasonable means associated with the Work, such party or parties. If applicable, that credit must be given in the particular way made known by the Original Author and otherwise as reasonable to the medium or means You are utilizing, by conveying the identity of the Original Author and the other designated party or parties (if applicable); the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit. + + c. False attribution prohibited. Except as otherwise agreed in writing by the Licensor, if You publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works in accordance with this Licence, You must not falsely attribute the Work to someone other than the Original Author. + + d. Prejudice to honour or reputation prohibited. Except as otherwise agreed in writing by the Licensor, if you publish, communicate to the public, distribute, publicly exhibit or display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must not do anything that results in a material distortion of, the mutilation of, or a material alteration to, the Work that is prejudicial to the Original Author's honour or reputation, and You must not do anything else in relation to the Work that is prejudicial to the Original Author's honour or reputation. + +5. Disclaimer. + +EXCEPT AS EXPRESSLY STATED IN THIS LICENCE OR OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, AND TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK "AS-IS" AND MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS OR ACCURACY OF THE WORK, OR OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. + +6. Limitation on Liability. + +TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, AND EXCEPT FOR ANY LIABILITY ARISING FROM CONTRARY MUTUAL AGREEMENT AS REFERRED TO IN SECTION 5, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) FOR ANY LOSS OR DAMAGE WHATSOEVER, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THIS LICENCE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +If applicable legislation implies warranties or conditions, or imposes obligations or liability on the Licensor in respect of this Licence that cannot be wholly or partly excluded, restricted or modified, the Licensor's liability is limited, to the full extent permitted by the applicable legislation, at its option, to: + + a. in the case of goods, any one or more of the following: + + i. the replacement of the goods or the supply of equivalent goods; + + ii. the repair of the goods; + + iii. the payment of the cost of replacing the goods or of acquiring equivalent goods; + + iv. the payment of the cost of having the goods repaired; or + + b. in the case of services: + + i. the supplying of the services again; or + + ii. the payment of the cost of having the services supplied again. + +7. Termination. + + a. This Licence and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this Licence. Individuals or entities who have received Derivative Works or Collective Works from You under this Licence, however, will not have their licences terminated provided such individuals or entities remain in full compliance with those licences. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this Licence. + + b. Subject to the above terms and conditions, the licence granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different licence terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this Licence (or any other licence that has been, or is required to be, granted under the terms of this Licence), and this Licence will continue in full force and effect unless terminated as stated above. + +8. Miscellaneous. + + a. Each time You publish, communicate to the public, distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a licence to the Work on the same terms and conditions as the licence granted to You under this Licence. + + b. Each time You publish, communicate to the public, distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a licence to the original Work on the same terms and conditions as the licence granted to You under this Licence. + + c. If any provision of this Licence is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Licence, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + + d. No term or provision of this Licence shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. + + e. This Licence constitutes the entire agreement between the parties with respect to the Work licensed here. To the full extent permitted by applicable law, there are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This Licence may not be modified without the mutual written agreement of the Licensor and You. + + f. The construction, validity and performance of this Licence shall be governed by the laws in force in New South Wales, Australia. + +Creative Commons is not a party to this Licence, and, to the full extent permitted by applicable law, makes no representation or warranty whatsoever in connection with the Work. To the full extent permitted by applicable law, Creative Commons will not be liable to You or any party on any legal theory (including, without limitation, negligence) for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this licence. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. + +Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, neither party will use the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. + +Creative Commons may be contacted at https://creativecommons.org/. diff --git a/options/license/OPUBL-1.0 b/options/license/OPUBL-1.0 new file mode 100644 index 0000000000000..1386621e0ff00 --- /dev/null +++ b/options/license/OPUBL-1.0 @@ -0,0 +1,78 @@ +Open Publication License + +v1.0, 8 June 1999 + +I. REQUIREMENTS ON BOTH UNMODIFIED AND MODIFIED VERSIONS + +The Open Publication works may be reproduced and distributed in whole or in part, in any medium physical or electronic, provided that the terms of this license are adhered to, and that this license or an incorporation of it by reference (with any options elected by the author(s) and/or publisher) is displayed in the reproduction. + +Proper form for an incorporation by reference is as follows: + + Copyright (c) by . This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, vX.Y or later (the latest version is presently available at http://www.opencontent.org/openpub/). + +The reference must be immediately followed with any options elected by the author(s) and/or publisher of the document (see section VI). + +Commercial redistribution of Open Publication-licensed material is permitted. + +Any publication in standard (paper) book form shall require the citation of the original publisher and author. The publisher and author's names shall appear on all outer surfaces of the book. On all outer surfaces of the book the original publisher's name shall be as large as the title of the work and cited as possessive with respect to the title. + +II. COPYRIGHT + +The copyright to each Open Publication is owned by its author(s) or designee. + +III. SCOPE OF LICENSE + +The following license terms apply to all Open Publication works, unless otherwise explicitly stated in the document. + +Mere aggregation of Open Publication works or a portion of an Open Publication work with other works or programs on the same media shall not cause this license to apply to those other works. The aggregate work shall contain a notice specifying the inclusion of the Open Publication material and appropriate copyright notice. + +SEVERABILITY. If any part of this license is found to be unenforceable in any jurisdiction, the remaining portions of the license remain in force. + +NO WARRANTY. Open Publication works are licensed and provided "as is" without warranty of any kind, express or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose or a warranty of non-infringement. + +IV. REQUIREMENTS ON MODIFIED WORKS + +All modified versions of documents covered by this license, including translations, anthologies, compilations and partial documents, must meet the following requirements: + 1. The modified version must be labeled as such. + 2. The person making the modifications must be identified and the modifications dated. + 3. Acknowledgement of the original author and publisher if applicable must be retained according to normal academic citation practices. + 4. The location of the original unmodified document must be identified. + 5. The original author's (or authors') name(s) may not be used to assert or imply endorsement of the resulting document without the original author's (or authors') permission. + +V. GOOD-PRACTICE RECOMMENDATIONS + +In addition to the requirements of this license, it is requested from and strongly recommended of redistributors that: + 1. If you are distributing Open Publication works on hardcopy or CD-ROM, you provide email notification to the authors of your intent to redistribute at least thirty days before your manuscript or media freeze, to give the authors time to provide updated documents. This notification should describe modifications, if any, made to the document. + 2. All substantive modifications (including deletions) be either clearly marked up in the document or else described in an attachment to the document. + 3. Finally, while it is not mandatory under this license, it is considered good form to offer a free copy of any hardcopy and CD-ROM expression of an Open Publication-licensed work to its author(s). + +VI. LICENSE OPTIONS + +The author(s) and/or publisher of an Open Publication-licensed document may elect certain options by appending language to the reference to or copy of the license. These options are considered part of the license instance and must be included with the license (or its incorporation by reference) in derived works. + +A. To prohibit distribution of substantively modified versions without the explicit permission of the author(s). "Substantive modification" is defined as a change to the semantic content of the document, and excludes mere changes in format or typographical corrections. + +To accomplish this, add the phrase `Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.' to the license reference or copy. + +B. To prohibit any publication of this work or derivative works in whole or in part in standard (paper) book form for commercial purposes is prohibited unless prior permission is obtained from the copyright holder. + +To accomplish this, add the phrase 'Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.' to the license reference or copy. + +OPEN PUBLICATION POLICY APPENDIX: + +(This is not considered part of the license.) + +Open Publication works are available in source format via the Open Publication home page at http://works.opencontent.org/. + +Open Publication authors who want to include their own license on Open Publication works may do so, as long as their terms are not more restrictive than the Open Publication license. + +If you have questions about the Open Publication License, please contact David Wiley, and/or the Open Publication Authors' List at opal@opencontent.org, via email. + +To subscribe to the Open Publication Authors' List: +Send E-mail to opal-request@opencontent.org with the word "subscribe" in the body. + +To post to the Open Publication Authors' List: +Send E-mail to opal@opencontent.org or simply reply to a previous post. + +To unsubscribe from the Open Publication Authors' List: +Send E-mail to opal-request@opencontent.org with the word "unsubscribe" in the body. diff --git a/options/locale/locale_bg-BG.ini b/options/locale/locale_bg-BG.ini index 834c88e1775df..6f61799f279f2 100644 --- a/options/locale/locale_bg-BG.ini +++ b/options/locale/locale_bg-BG.ini @@ -250,7 +250,6 @@ openid_connect_submit=Свързване openid_connect_title=Свързване към съществуващ профил openid_register_title=Създай нов акаунт openid_signin_desc=Въведете вашето OpenID URI. Например: https://anne.me, bob.openid.org.cn или gnusocial.net/carry. -disable_forgot_password_mail=Възстановяването на профили е изключено. Моля обърнете се към администратора на сайта. authorize_application=Оторизиране на приложение authorize_redirect_notice=Ще бъдете пренасочени към %s ако оторизирате това приложение. authorize_application_created_by=Това приложение е създадено от %s. @@ -490,6 +489,7 @@ delete_account_title=Изтриване на потребителски акау email_notifications.disable=Изключване на известията по имейл + [repo] owner=Притежател repo_name=Име на хранилището diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 8fbdfd4a557f7..5fac10ee94d56 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -300,7 +300,6 @@ openid_connect_desc=Zvolené OpenID URI není známé. Přidružte nový účet openid_register_title=Vytvořit nový účet openid_register_desc=Zvolené OpenID URI není známé. Přidružte nový účet zde. openid_signin_desc=Zadejte své OpenID URI. Například: https://anne.me, bob.openid.org.cn nebo gnusocial.net/carry. -disable_forgot_password_mail=Obnovení účtu je zakázané. Prosíme, kontaktujte správce systému. email_domain_blacklisted=Nemůžete se registrovat s vaší e-mailovou adresou. authorize_application=Autorizovat aplikaci authorize_redirect_notice=Budete přesměrováni na %s, pokud autorizujete tuto aplikaci. @@ -681,6 +680,7 @@ email_notifications.onmention=E-mail pouze při zmínce email_notifications.disable=Zakázat e-mailová oznámení email_notifications.submit=Nastavit předvolby e-mailu + [repo] new_repo_helper=Repozitář obsahuje všechny projektové soubory, včetně historie revizí. Už ho máte jinde? Migrovat repozitář. owner=Vlastník @@ -1741,7 +1741,6 @@ settings.event_pull_request_review_desc=Požadavek na natažení schválen, odm settings.event_pull_request_sync=Požadavek na natažení synchronizován settings.event_pull_request_sync_desc=Požadavek na natažení synchronizován. settings.branch_filter=Filtr větví -settings.branch_filter_desc=Povolené větve pro události nahrání, vytvoření větve a smazání větve jsou určeny pomocí zástupného vzoru. Pokud je prázdný nebo *, všechny události jsou ohlášeny. Podívejte se na dokumentaci syntaxe na github.com/gobwas/glob. Příklady: master, {master,release*}. settings.active=Aktivní settings.active_helper=Informace o spuštěných událostech budou odeslány na URL webového háčku. settings.add_hook_success=Webový háček byl přidán. @@ -1811,7 +1810,6 @@ settings.dismiss_stale_approvals_desc=Pokud budou do větve nahrány nové reviz settings.require_signed_commits=Vyžadovat podepsané revize settings.require_signed_commits_desc=Odmítnout nahrání do této větve pokud nejsou podepsaná nebo jsou neověřitelná. settings.protect_protected_file_patterns=Chráněné vzory souborů (oddělené středníkem „\;“): -settings.protect_protected_file_patterns_desc=Chráněné soubory, které nemají povoleno být měněny přímo, i když uživatel má právo přidávat, upravovat nebo mazat soubory v této větvi. Více vzorů lze oddělit pomocí středníku („\;“). Podívejte se na github.com/gobwas/glob dokumentaci pro syntaxi vzoru. Příklady: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Zapnout ochranu settings.delete_protected_branch=Vypnout ochranu settings.update_protect_branch_success=Ochrana větví pro větev „%s“ byla aktualizována. diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index e8f2d1d58740c..0320102724eba 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -83,6 +83,7 @@ add=Hinzufügen add_all=Alle hinzufügen remove=Löschen remove_all=Alle entfernen +edit=Bearbeiten write=Verfassen preview=Vorschau @@ -302,7 +303,8 @@ openid_connect_desc=Die gewählte OpenID-URI ist unbekannt. Ordne sie hier einem openid_register_title=Neues Konto einrichten openid_register_desc=Die gewählte OpenID-URI ist unbekannt. Ordne sie hier einem neuen Account zu. openid_signin_desc=Gib deine OpenID-URI ein. Zum Beispiel: https://anne.me, bob.openid.org.cn oder gnusocial.net/carry. -disable_forgot_password_mail=Die Kontowiederherstellung ist deaktiviert. Bitte wende dich an den Administrator. +disable_forgot_password_mail=Die Kontowiederherstellung ist deaktiviert, da keine E-Mail eingerichtet ist. Bitte kontaktiere den zuständigen Administrator. +disable_forgot_password_mail_admin=Die Kontowiederherstellung ist nur verfügbar, wenn eine E-Mail eingerichtet wurde. Bitte richte eine E-Mail Adresse ein, um die Kontowiederherstellung freizuschalten. email_domain_blacklisted=Du kannst dich nicht mit deiner E-Mail-Adresse registrieren. authorize_application=Anwendung autorisieren authorize_redirect_notice=Du wirst zu %s weitergeleitet, wenn du diese Anwendung autorisierst. @@ -414,6 +416,7 @@ email_error=` ist keine gültige E-Mail-Adresse.` url_error=` ist keine gültige URL.` include_error=` muss den Text „%s“ enthalten.` glob_pattern_error=` Der Glob Pattern ist ungültig: %s.` +regex_pattern_error=` regex ist ungültig: %s.` unknown_error=Unbekannter Fehler: captcha_incorrect=Der eingegebene CAPTCHA-Code ist falsch. password_not_match=Die Passwörter stimmen nicht überein. @@ -721,6 +724,14 @@ email_notifications.onmention=Nur E-Mail bei Erwähnung email_notifications.disable=E-Mail Benachrichtigungen deaktivieren email_notifications.submit=E-Mail-Einstellungen festlegen +visibility=Nutzer Sichtbarkeit +visibility.public=Öffentlich +visibility.public_tooltip=Für alle Nutzer sichtbar +visibility.limited=Begrenzt +visibility.limited_tooltip=Nur für eingeloggte Benutzer sichtbar +visibility.private=Privat +visibility.private_tooltip=Nur für Organisationsmitglieder sichtbar + [repo] new_repo_helper=Ein Repository enthält alle Projektdateien, einschließlich des Änderungsverlaufs. Schon woanders vorhanden? Migriere das Repository. owner=Besitzer @@ -798,6 +809,7 @@ delete_preexisting_label=Löschen delete_preexisting=Vorhandene Dateien löschen delete_preexisting_content=Dateien in %s löschen delete_preexisting_success=Nicht übernommene Dateien in %s gelöscht +blame_prior=Blame vor dieser Änderung anzeigen transfer.accept=Übertragung Akzeptieren transfer.accept_desc=Übertragung nach "%s" @@ -1801,7 +1813,6 @@ settings.event_pull_request_review_desc=Pull-Request genehmigt, abgelehnt oder K settings.event_pull_request_sync=Pull-Request synchronisiert settings.event_pull_request_sync_desc=Pull-Request synchronisiert. settings.branch_filter=Branch-Filter -settings.branch_filter_desc=Branch-Whitelist für Push, Brancherstellung und Branchlöschung, als glob pattern. Ist dieser leer oder nur * angegeben, werden Ereignisse für alle Branches gemeldet. Siehe Dokumentation unter github.com/gobwas/glob für die Syntax. Beispiele: master, {master,release*}. settings.active=Aktiv settings.active_helper=Informationen über ausgelöste Ereignisse werden an diese Webhook-URL gesendet. settings.add_hook_success=Webhook wurde hinzugefügt. @@ -1871,7 +1882,6 @@ settings.dismiss_stale_approvals_desc=Wenn neue Commits gepusht werden, die den settings.require_signed_commits=Signierte Commits erforderlich settings.require_signed_commits_desc=Pushes auf diesen Branch ablehnen, wenn Commits nicht signiert oder nicht überprüfbar sind. settings.protect_protected_file_patterns=Geschützte Dateimuster (durch Semikolon getrennt '\;'): -settings.protect_protected_file_patterns_desc=Geschützte Dateien, die nicht direkt geändert werden dürfen, auch wenn der Benutzer die Rechte hat, Dateien in diesem Branch hinzuzufügen, zu bearbeiten oder zu löschen. Mehrere Muster können mit Semikolon ('\;') getrennt werden. Siehe github.com/gobwas/glob Dokumentation für Mustersyntax. Beispiele: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Schutz aktivieren settings.delete_protected_branch=Schutz deaktivieren settings.update_protect_branch_success=Branch-Schutz für den Branch „%s“ wurde geändert. @@ -1890,6 +1900,15 @@ settings.choose_branch=Wähle einen Branch … settings.no_protected_branch=Es gibt keine geschützten Branches. settings.edit_protected_branch=Bearbeiten settings.protected_branch_required_approvals_min=Die Anzahl der erforderlichen Zustimmungen darf nicht negativ sein. +settings.tags=Tags +settings.tags.protection=Tag-Schutz +settings.tags.protection.pattern=Tag Muster +settings.tags.protection.allowed=Erlaubt +settings.tags.protection.allowed.users=Erlaubte Benutzer +settings.tags.protection.allowed.teams=Erlaubte Teams +settings.tags.protection.allowed.noone=Niemand +settings.tags.protection.create=Tag schützen +settings.tags.protection.none=Es gibt keine geschützten Tags. settings.bot_token=Bot-Token settings.chat_id=Chat-ID settings.matrix.homeserver_url=Homeserver-URL @@ -2017,6 +2036,7 @@ release.deletion_tag_desc=Löscht dieses Tag aus dem Projektarchiv. Repository-I release.deletion_tag_success=Der Tag wurde gelöscht. release.tag_name_already_exist=Ein Release mit diesem Tag existiert bereits. release.tag_name_invalid=Der Tag-Name ist ungültig. +release.tag_name_protected=Der Tag-Name ist geschützt. release.tag_already_exist=Dieser Tag-Name existiert bereits. release.downloads=Downloads release.download_count=Downloads: %s diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a809f49eebae8..dcdfa611ec950 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -303,7 +303,8 @@ openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new openid_register_title = Create new account openid_register_desc = The chosen OpenID URI is unknown. Associate it with a new account here. openid_signin_desc = Enter your OpenID URI. For example: https://anne.me, bob.openid.org.cn or gnusocial.net/carry. -disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator. +disable_forgot_password_mail = Account recovery is disabled because no email is set up. Please contact your site administrator. +disable_forgot_password_mail_admin = Account recovery is only available when email is set up. Please set up email to enable account recovery. email_domain_blacklisted = You cannot register with your email address. authorize_application = Authorize Application authorize_redirect_notice = You will be redirected to %s if you authorize this application. @@ -312,7 +313,6 @@ authorize_application_description = If you grant the access, it will be able to authorize_title = Authorize "%s" to access your account? authorization_failed = Authorization failed authorization_failed_desc = The authorization failed because we detected an invalid request. Please contact the maintainer of the app you've tried to authorize. -disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator. sspi_auth_failed = SSPI authentication failed password_pwned = The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password. password_pwned_err = Could not complete request to HaveIBeenPwned @@ -724,6 +724,14 @@ email_notifications.onmention = Only Email on Mention email_notifications.disable = Disable Email Notifications email_notifications.submit = Set Email Preference +visibility = User visibility +visibility.public = Public +visibility.public_tooltip = Visible to all users +visibility.limited = Limited +visibility.limited_tooltip = Visible to logged in users only +visibility.private = Private +visibility.private_tooltip = Visible only to organization members + [repo] new_repo_helper = A repository contains all project files, including revision history. Already have it elsewhere? Migrate repository. owner = Owner @@ -801,6 +809,7 @@ delete_preexisting_label = Delete delete_preexisting = Delete pre-existing files delete_preexisting_content = Delete files in %s delete_preexisting_success = Deleted unadopted files in %s +blame_prior = View blame prior to this change transfer.accept = Accept Transfer transfer.accept_desc = Transfer to "%s" diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 017b83a9b3006..40fc8d7af61b9 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -302,7 +302,6 @@ openid_connect_desc=La URI OpenID elegida es desconocida. Asóciela a una nueva openid_register_title=Crear una nueva cuenta openid_register_desc=La URI OpenID elegida es desconocida. Asóciela a una nueva cuenta aquí. openid_signin_desc=Introduzca su URI OpenID. Por ejemplo: https://anne.me, bob.openid.org.cn o gnusocial.net/carry. -disable_forgot_password_mail=La recuperación de cuentas está desactivada. Por favor, contacte con el administrador del sitio. email_domain_blacklisted=No puede registrarse con su correo electrónico. authorize_application=Autorizar aplicación authorize_redirect_notice=Será redirigido a %s si autoriza esta aplicación. @@ -414,6 +413,7 @@ email_error=` no es una dirección de correo válida.` url_error=` no es una URL válida.` include_error=` debe contener la subcadena '%s'.` glob_pattern_error=` el patrón globo no es válido: %s.` +regex_pattern_error=` el patrón de regex no es válido: %s.` unknown_error=Error desconocido: captcha_incorrect=El código CAPTCHA no es correcto. password_not_match=Las contraseñas no coinciden. @@ -721,6 +721,7 @@ email_notifications.onmention=Enviar correo sólo al ser mencionado email_notifications.disable=Deshabilitar las notificaciones por correo electrónico email_notifications.submit=Establecer preferencias de correo electrónico + [repo] new_repo_helper=Un repositorio contiene todos los archivos del proyecto, incluyendo el historial de revisiones. ¿Ya lo tiene en otro lugar? Migrar repositorio. owner=Propietario @@ -1801,7 +1802,7 @@ settings.event_pull_request_review_desc=Pull request aprobado, rechazado o comen settings.event_pull_request_sync=Pull Request sincronizado settings.event_pull_request_sync_desc=Pull request sincronizado. settings.branch_filter=Filtro de rama -settings.branch_filter_desc=Lista blanca de rama para eventos de push, creación de rama y eliminación de rama, especificados como patrón globo. Si está vacío o *, se reportan eventos para todas las ramas. Ver github.com/gobwas/glob documentación para la sintaxis. Ejemplos: master, {master,release*}. +settings.branch_filter_desc=Lista blanca de rama para eventos de push, creación de rama y eliminación de rama, especificados como patrón globo. Si está vacío o *, se reportan eventos para todas las ramas. Ver github.com/gobwas/glob documentación para la sintaxis. Ejemplos: master, {master,release*}. settings.active=Activo settings.active_helper=La información sobre los eventos desencadenados se enviará a esta URL de webhook. settings.add_hook_success=El webhook ha sido añadido. @@ -1871,7 +1872,6 @@ settings.dismiss_stale_approvals_desc=Cuando los nuevos commits que cambien el c settings.require_signed_commits=Requiere commits firmados settings.require_signed_commits_desc=Rechazar push en esta rama si los commits no están firmados o no son verificables. settings.protect_protected_file_patterns=Patrones de archivos protegidos (separados con punto y coma '\;'): -settings.protect_protected_file_patterns_desc=No se permite cambiar directamente archivos protegidos, incluso si el usuario tiene derechos para añadir, editar o eliminar archivos en esta rama. Se pueden separar múltiples patrones usando punto y coma ('\;'). Véase la documentación de github.com/gobwas/glob sobre sintaxis de patrones. Ejemplos: .drone.yml,/docs/**/*.txt. settings.add_protected_branch=Activar protección settings.delete_protected_branch=Desactivar protección settings.update_protect_branch_success=La protección de la rama '%s' ha sido actualizada. diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index e97a3b0229f15..6ed6ded4a6e5c 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -287,7 +287,6 @@ openid_connect_desc=نشانی OpenID URI وارد شده شناخته نشد. openid_register_title=ایجاد یک حساب جدید openid_register_desc=نشانی URI وارد شده شناخته نشد. آن را با یک حساب جدید متصل کنید. openid_signin_desc=نوع حساب کاربری خود را وارد کنید. به عنوان مثال: https://anne.me و bob.openid.org.cn یا gnusocial.net/carry. -disable_forgot_password_mail=بازیابی حساب غیر فعال شده است. لطفا با مدیر سایت تماس بگیرید. email_domain_blacklisted=شما نمیتوانید با ایمیل خود ثبت نام کنید. authorize_application=برنامه احراز هویت authorize_redirect_notice=اگر شما این برنامه را تایید کنید، به %s منتقل خواهید شد. @@ -635,6 +634,7 @@ email_notifications.onmention=فقط یادآوری توسط ایمیل email_notifications.disable=غیرفعال‌ کردن اعلان‌های ایمیل email_notifications.submit=ثبت اولویت ایمیل + [repo] owner=مالک repo_name=نام مخزن @@ -1460,7 +1460,6 @@ settings.event_issue_comment=دیدگاه های مسئله settings.event_issue_comment_desc=نظر در مسئله ایجاد شد، ویرایش شد یا حذف شد. settings.event_pull_request=تقاضای واکشی settings.branch_filter=صافی شاخه -settings.branch_filter_desc=لیست سفید برای درج در شاخه، سازنده شاخه و حذف کننده رخداد ها، به عنوان الگوی قطره‌ای تعریف میشوند. اگر خالی یا * باشد. رخداد های تمامی شاخه های گزارش می شوند. به github.com/gobwas/glob برای مستندات املای آن نگاه کنید. مثال ها: master, {master,release*}. settings.active=فعال settings.active_helper=اطلاعات درباره کشیده شدن ماشه رویدادها به این نشانی هوک تحت وب ارسال خواهد شد. settings.add_hook_success=یک هوک تحت وب جدید افزوده شده است. diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 10b6bbad99a47..9a19f2d11ba09 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -251,7 +251,6 @@ openid_connect_desc=Valittu OpenID-osoite on tuntematon. Liitä se uuteen tiliin openid_register_title=Luo uusi tili openid_register_desc=Valittu OpenID-osoite on tuntematon. Liitä se uuteen tiliin täällä. openid_signin_desc=Anna OpenID-osoitteesi. Esimerkiksi: https://anne.me, bob.openid.org.cn tai gnusocial.net/carry. -disable_forgot_password_mail=Tilin palautus ei ole käytössä. Ota yhteyttä sivuston ylläpitäjään. email_domain_blacklisted=Et voi rekisteröityä sähköpostiosoittellasi. authorize_application=Valtuuta sovellus authorize_redirect_notice=Sinut uudelleen ohjataan osoitteeseen %s jos valtuutat tämän sovelluksen. @@ -496,6 +495,7 @@ delete_account_title=Poista käyttäjätili email_notifications.enable=Ota käyttöön sähköpostiilmoitukset + [repo] owner=Omistaja repo_name=Repon nimi diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 493c95058189d..b9ce6d87c60e1 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -302,7 +302,6 @@ openid_connect_desc=L'URI OpenID choisie est inconnue. Associez-le à un nouveau openid_register_title=Créer un nouveau compte openid_register_desc=L'URI OpenID choisie est inconnue. Associez-le à un nouveau compte ici. openid_signin_desc=Veuillez entrer votre URI OpenID. Par exemple: https://anne.me, bob.openid.org.cn ou gnusocial.net/charles. -disable_forgot_password_mail=La récupération de compte est désactivée. Veuillez contacter l'administrateur du site. email_domain_blacklisted=Vous ne pouvez pas vous enregistrer avec votre adresse e-mail. authorize_application=Autoriser l'application authorize_redirect_notice=Vous serez redirigé vers %s si vous autorisez cette application. @@ -694,6 +693,7 @@ email_notifications.onmention=N'envoyer un e-mail que si vous êtes mentionné email_notifications.disable=Désactiver les notifications par email email_notifications.submit=Définir la préférence e-mail + [repo] new_repo_helper=Un dépôt contient tous les fichiers du projet, y compris l'historique des révisions. Vous l'avez déjà ailleurs ? Migrer le dépôt. owner=Propriétaire @@ -1762,7 +1762,6 @@ settings.event_pull_request_review_desc=Demande d'ajout approvée, rejetée ou c settings.event_pull_request_sync=Demande d'ajout synchronisée settings.event_pull_request_sync_desc=Demande d'ajout synchronisée. settings.branch_filter=Filtre de branche -settings.branch_filter_desc=Liste blanche pour les évènements de poussage, de création et de suppression de branche, spécifiés par un motif de développement. Si ce champ est vide ou vaut *, ces évènements sont rapportés pour toutes les branches . Voir la documentation pour la syntaxe sur github.com/gobwas/glob. Exemples : master, {master,release*}. settings.active=Actif settings.active_helper=Les informations sur les événements déclenchés seront envoyées à cette url de Webhook. settings.add_hook_success=Nouveau Webhook ajouté. @@ -1832,7 +1831,6 @@ settings.dismiss_stale_approvals_desc=Quand de nouvelles révisions qui changent settings.require_signed_commits=Exiger des révisions signées settings.require_signed_commits_desc=Rejeter les pushs vers cette branche s’ils ne sont pas signés ou vérifiables. settings.protect_protected_file_patterns=Motifs des fichiers protégés (séparés par un point-virgule '\;') : -settings.protect_protected_file_patterns_desc=Fichiers protégés dont la modification directe est interdite même si l’utilisateur a les droits d’ajouter, éditer ou supprimer des fichiers dans cette branche. Plusieurs motifs peuvent être séparés par un point-virgule ('\;'). Consultez la documentation de github.com/gobwas/glob sur la syntaxe des motifs. Exemples: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Activer la protection settings.delete_protected_branch=Désactiver la protection settings.update_protect_branch_success=La protection de branche à été mise à jour pour la branche "%s". diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 953d5ab8ac9c1..46c12c4106524 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -282,7 +282,6 @@ openid_connect_desc=A kiválasztott OpenID URI ismeretlen. Itt társíthatja egy openid_register_title=Új fiók létrehozása openid_register_desc=A kiválasztott OpenID URI ismeretlen. Itt társíthatja egy új fiókkal. openid_signin_desc=Adja meg az OpenID URI-jét. Például https://anne.me, bob.openid.org.cn vagy gnusocial.net/carry. -disable_forgot_password_mail=A felhasználó visszaállítás le van tiltva. Kérjük, lépjen kapcsolatba az oldal adminisztrátorával. email_domain_blacklisted=Ezzel az email címmel nem regisztrálhat. authorize_application=Alkalmazás engedélyezése authorize_redirect_notice=Ha engedélyezi ezt az alkalmazást, akkor átirányításra kerül a %s címre. @@ -598,6 +597,7 @@ email_notifications.onmention=Email küldése csak megjelölés esetén email_notifications.disable=Email értesítés kikapcsolása email_notifications.submit=E-mail beállítások megadása + [repo] owner=Tulajdonos repo_name=Tároló neve diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index e7d2113452ca9..cb561b84593c0 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -269,7 +269,6 @@ openid_connect_desc=OpenID URI yang dipilih tak dikenal. Asosiasikan dengan akun openid_register_title=Buat akun baru openid_register_desc=OpenID URI yang dipilih tak dikenal. Asosiasikan dengan akun baru disini. openid_signin_desc=Masukkan URI OpenID Anda. Misalnya: https://anne.me, bob.openid.org.cn, atau gnusocial.net/carry. -disable_forgot_password_mail=Pemulihan akun ditiadakan. Hubungi admin situs Anda. email_domain_blacklisted=Anda tidak dapat mendaftar dengan alamat email. authorize_application=Izinkan aplikasi authorize_redirect_notice=Anda akan dialihkan ke %s apabila Anda mengizinkan aplikasi ini. @@ -598,6 +597,7 @@ email_notifications.enable=Aktifkan Pemberitahuan Surel email_notifications.disable=Nonaktifkan Email Notifikasi email_notifications.submit=Pasang Pengaturan Email + [repo] owner=Pemilik repo_name=Nama Repositori diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index a59531b2b6472..f92c5c794a14e 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -300,7 +300,6 @@ openid_connect_desc=L'URI OpenID scelto è sconosciuto. Qui puoi associarlo a un openid_register_title=Crea Nuovo Account openid_register_desc=L'URI OpenID scelto è sconosciuto. Qui puoi associarlo a un nuovo account. openid_signin_desc=Inserisci il tuo URI OpenID. Ad esempio: https://anne.me, bob.openid.org.cn o gnusocial.net/carry. -disable_forgot_password_mail=La reimpostazione della password è disabilitata. Si prega di contattare l'amministratore del sito. email_domain_blacklisted=Non è possibile registrarsi con il proprio indirizzo email. authorize_application=Autorizza applicazione authorize_redirect_notice=Verrai reindirizzato a %s se autorizzi questa applicazione. @@ -668,6 +667,7 @@ email_notifications.onmention=Solo email su Menzione email_notifications.disable=Disabilita notifiche email email_notifications.submit=Imposta Preferenze Email + [repo] owner=Proprietario repo_name=Nome Repository @@ -1612,7 +1612,6 @@ settings.event_pull_request_label=Pull Request etichettata settings.event_pull_request_label_desc=Etichette Pull request aggiornate o cancellate. settings.event_pull_request_sync_desc=Pull request sincronizzata. settings.branch_filter=Filtro branch -settings.branch_filter_desc=Whitelist branch per gli eventi di push, creazione e cancellazione del ramo, specificati con un pattern globale. Se vuoto o *, gli eventi per tutti i rami vengono segnalati. Vedi github.com/gobwas/glob documentazione per la sintassi. Esempi: master, {master,release*}. settings.active=Attivo settings.active_helper=Le informazioni sugli eventi innescati saranno inviate a questo URL del webhook. settings.add_hook_success=Il webhook è stato aggiunto. diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 45ca0da2ce095..9a5a56e7998e6 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -83,6 +83,7 @@ add=追加 add_all=すべて追加 remove=除去 remove_all=すべて除去 +edit=編集 write=書き込み preview=プレビュー @@ -302,7 +303,8 @@ openid_connect_desc=選択したOpenID URIは未登録です。 ここで新し openid_register_title=アカウント新規作成 openid_register_desc=選択したOpenID URIは未登録です。 ここで新しいアカウントと関連付けます。 openid_signin_desc=あなたのOpenID URIを入力してください。 例: https://anne.me、bob.openid.org.cn、nusocial.net/carry -disable_forgot_password_mail=アカウント回復機能は無効になっています。 サイト管理者にお問い合わせください。 +disable_forgot_password_mail=メール送信設定が無いためアカウントの回復は無効になっています。 サイト管理者にお問い合わせください。 +disable_forgot_password_mail_admin=アカウントの回復はメール送信が設定済みの場合だけ使用できます。 アカウントの回復を有効にするにはメール送信を設定してください。 email_domain_blacklisted=あなたのメールアドレスでは登録することはできません。 authorize_application=アプリケーションを許可 authorize_redirect_notice=このアプリケーションを許可すると %s にリダイレクトします。 @@ -316,26 +318,64 @@ password_pwned=あなたが選択したパスワードは、過去の情報漏 password_pwned_err=HaveIBeenPwnedへのリクエストを完了できませんでした [mail] +view_it_on=%s で見る +link_not_working_do_paste=開かないですか? コピーしてブラウザーに貼り付けてみてください。 +hi_user_x=こんにちは、%s さん。 activate_account=あなたのアカウントをアクティベートしてください。 +activate_account.title=%s さん、アカウントをアクティベートしてください +activate_account.test_1=こんにちは、%[1]s さん。 %[2]s へのご登録ありがとうございます! +activate_account.test_2=あなたのアカウントを有効化するため、%s以内に次のリンクをクリックしてください: activate_email=メール アドレスを確認します +activate_email.title=%s さん、メールアドレス確認をお願いします +activate_email.text=あなたのメールアドレスを確認するため、%s以内に次のリンクをクリックしてください: register_notify=Giteaへようこそ +register_notify.title=%[1]s さん、%[2]s にようこそ +register_notify.text_1=これは %s への登録確認メールです! +register_notify.text_2=あなたはユーザー名 %s でログインできるようになりました。 +register_notify.text_3=このアカウントがあなたに作成されたものであれば、最初にパスワードを設定してください。 reset_password=アカウントを回復 +reset_password.title=%s さん、あなたのアカウントの回復がリクエストされました +reset_password.text=あなたのアカウントを回復するには、%s以内に次のリンクをクリックしてください: register_success=登録が完了しました - +issue_assigned.pull=リポジトリ %[3]s で @%[1]s さんが、あなたをプルリクエスト %[2]s の担当者にしました。 +issue_assigned.issue=リポジトリ %[3]s で @%[1]s さんが、あなたを課題 %[2]s の担当者にしました。 + +issue.x_mentioned_you=@%s さんが、あなたにメンションしました: +issue.action.force_push=%[1]s さんが %[2]s に強制プッシュしました。(%[3]s から %[4]s へ) +issue.action.push_1=@%[1]s さんが %[2]s にコミット1件をプッシュしました。 +issue.action.push_n=@%[1]s さんが %[2]s にコミット%[3]d件をプッシュしました。 +issue.action.close=@%[1]s さんが #%[2]d をクローズしました。 +issue.action.reopen=@%[1]s さんが #%[2]d を再オープンしました。 +issue.action.merge=@%[1]s さんが #%[2]d を %[3]s にマージしました。 +issue.action.approve=@%[1]s さんがプルリクエストを承認しました。 +issue.action.reject=@%[1]s さんがプルリクエストに変更を要請しました。 +issue.action.review=@%[1]s さんがプルリクエストにコメントしました。 +issue.action.review_dismissed=@%[1]s さんが、プルリクエストに対する %[2]s さんの最新レビューを棄却しました。 +issue.action.ready_for_review=@%[1]s さんが、プルリクエストをレビュー可能な状態にしました。 +issue.action.new=@%[1]s さんが #%[2]d を作成しました。 +issue.in_tree_path=%s: release.new.subject=%[2]s の %[1]s がリリースされました +release.new.text=@%[1]s さんが %[3]s で %[2]s をリリースしました +release.title=タイトル: %s +release.note=リリースノート: +release.downloads=ダウンロード: +release.download.zip=ソースコード (ZIP) +release.download.targz=ソースコード (TAR.GZ) repo.transfer.subject_to=%s が "%s" を %s に移転しようとしています repo.transfer.subject_to_you=%s が "%s" をあなたに移転しようとしています repo.transfer.to_you=あなた +repo.transfer.body=承認または拒否するには %s を開きます。 もしくは単に無視してもかまいません。 repo.collaborator.added.subject=%s が %s にあなたを追加しました +repo.collaborator.added.text=あなたは次のリポジトリの共同作業者に追加されました: [modal] yes=はい @@ -376,6 +416,7 @@ email_error=`は有効なメールアドレスではありません。` url_error=`は有効なURLではありません。` include_error=`は文字列 '%s' を含んでいる必要があります。` glob_pattern_error=`のglobパターンが不正です: %s.` +regex_pattern_error=`の正規表現パターンが不正です: %s.` unknown_error=不明なエラー: captcha_incorrect=CAPTCHAコードが正しくありません。 password_not_match=パスワードが一致しません。 @@ -683,6 +724,14 @@ email_notifications.onmention=メンションのみメール通知 email_notifications.disable=メール通知無効 email_notifications.submit=メール設定を保存 +visibility=ユーザーの公開範囲 +visibility.public=パブリック +visibility.public_tooltip=すべてのユーザーに表示します +visibility.limited=限定 +visibility.limited_tooltip=ログインしているユーザーにのみ表示します +visibility.private=プライベート +visibility.private_tooltip=組織のメンバーにのみ表示します + [repo] new_repo_helper=リポジトリには、プロジェクトのすべてのファイルとリビジョン履歴が入ります。 すでにほかの場所にありますか? リポジトリを移行 もどうぞ。 owner=オーナー @@ -760,6 +809,7 @@ delete_preexisting_label=削除 delete_preexisting=既存のファイルを削除 delete_preexisting_content=%s のファイルを削除します delete_preexisting_success=%s の未登録ファイルを削除しました +blame_prior=この変更より前のBlameを表示 transfer.accept=転送を承認 transfer.accept_desc="%s" に転送 @@ -1763,7 +1813,7 @@ settings.event_pull_request_review_desc=プルリクエストの承認・拒否 settings.event_pull_request_sync=プルリクエストの同期 settings.event_pull_request_sync_desc=プルリクエストが同期されたとき。 settings.branch_filter=ブランチ フィルター -settings.branch_filter_desc=プッシュ、ブランチ作成、ブランチ削除のイベントを通知するブランチを、globパターンで指定するホワイトリストです。 空か*のときは、すべてのブランチのイベントを通知します。 文法は github.com/gobwas/glob を参照してください。 例: master{master,release*} +settings.branch_filter_desc=プッシュ、ブランチ作成、ブランチ削除のイベントを通知するブランチを、globパターンで指定するホワイトリストです。 空か*のときは、すべてのブランチのイベントを通知します。 文法については github.com/gobwas/glob を参照してください。 例: master{master,release*} settings.active=有効 settings.active_helper=トリガーとなったイベントに関する情報が、このWebhookのURLに送信されます。 settings.add_hook_success=Webhookを追加しました。 @@ -1833,7 +1883,7 @@ settings.dismiss_stale_approvals_desc=プルリクエストの内容を変える settings.require_signed_commits=コミット署名必須 settings.require_signed_commits_desc=署名されていない場合、または署名が検証できなかった場合は、このブランチへのプッシュを拒否します。 settings.protect_protected_file_patterns=保護されるファイルのパターン (セミコロン'\;'で区切る): -settings.protect_protected_file_patterns_desc=保護されたファイルは、このブランチにファイルを追加・編集・削除する権限を持つユーザーであっても、そのままでは変更することはできません。 複数のパターンはセミコロン('\;')で区切ります。 パターンの文法については github.com/gobwas/glob を参照してください。 例: .drone.yml, /docs/**/*.txt +settings.protect_protected_file_patterns_desc=保護されたファイルは、このブランチにファイルを追加・編集・削除する権限を持つユーザーであっても、直接変更することができなくなります。 セミコロン('\;')で区切って複数のパターンを指定できます。 パターンの文法については github.com/gobwas/glob を参照してください。 例: .drone.yml, /docs/**/*.txt settings.add_protected_branch=保護を有効にする settings.delete_protected_branch=保護を無効にする settings.update_protect_branch_success=ブランチ '%s' の保護を更新しました。 @@ -1852,6 +1902,16 @@ settings.choose_branch=ブランチを選択… settings.no_protected_branch=保護しているブランチはありません。 settings.edit_protected_branch=編集 settings.protected_branch_required_approvals_min=必要な承認数は負の数にできません。 +settings.tags=タグ +settings.tags.protection=タグの保護 +settings.tags.protection.pattern=タグ名パターン +settings.tags.protection.allowed=許可 +settings.tags.protection.allowed.users=許可するユーザー +settings.tags.protection.allowed.teams=許可するチーム +settings.tags.protection.allowed.noone=なし +settings.tags.protection.create=タグを保護 +settings.tags.protection.none=タグは保護されていません。 +settings.tags.protection.pattern.description=ひとつのタグ名か、複数のタグにマッチするglobパターンまたは正規表現を使用できます。 詳しくは タグの保護ガイド をご覧ください。 settings.bot_token=Botトークン settings.chat_id=チャットID settings.matrix.homeserver_url=ホームサーバー URL @@ -1865,6 +1925,7 @@ settings.archive.success=リポジトリをアーカイブしました。 settings.archive.error=リポジトリのアーカイブ設定でエラーが発生しました。 詳細はログを確認してください。 settings.archive.error_ismirror=ミラーのリポジトリはアーカイブできません。 settings.archive.branchsettings_unavailable=ブランチ設定は、アーカイブリポジトリでは使用できません。 +settings.archive.tagsettings_unavailable=タグ設定は、アーカイブリポジトリでは使用できません。 settings.unarchive.button=アーカイブ解除 settings.unarchive.header=このリポジトリをアーカイブ解除 settings.unarchive.text=リポジトリのアーカイブを解除すると、コミット、プッシュ、新規の課題やプルリクエストを受け付けるよう元に戻されます。 @@ -1979,6 +2040,7 @@ release.deletion_tag_desc=リポジトリからこのタグを削除します。 release.deletion_tag_success=タグを削除しました。 release.tag_name_already_exist=このタグ名のリリースが既に存在します。 release.tag_name_invalid=タグ名が不正です。 +release.tag_name_protected=保護されているタグ名です。 release.tag_already_exist=このタグ名は既に存在します。 release.downloads=ダウンロード release.download_count=ダウンロード数: %s diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index e0b195d5e8f93..cb35373b185d3 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -557,6 +557,7 @@ delete_account_desc=이 계정을 정말로 삭제하시겠습니까? email_notifications.enable=이메일 알림 켜기 email_notifications.disable=이메일 알림 끄기 + [repo] owner=소유자 repo_name=저장소 이름 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 2fad43b54349d..f57fbf7225004 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -300,7 +300,6 @@ openid_connect_desc=Izvēlētais OpenID konts sistēmā netika atpazīts, bet J openid_register_title=Izveidot jaunu kontu openid_register_desc=Izvēlētais OpenID konts sistēmā netika atpazīts, bet Jūs to varat piesaistīt esošam kontam. openid_signin_desc=Ievadiet savu OpenID URI, piemēram: https://anna.me, peteris.openid.org.lv, gnusocial.net/janis. -disable_forgot_password_mail=Paroles atjaunošanas iespēja ir atslēgta. Sazinieties ar lapas administratoru. email_domain_blacklisted=Nav atļauts reģistrēties ar šādu e-pasta adresi. authorize_application=Autorizēt lietotni authorize_redirect_notice=Jūs tiksiet nosūtīts uz %s, ja autorizēsiet šo lietotni. @@ -675,6 +674,7 @@ email_notifications.onmention=Tikai, ja esmu pieminēts email_notifications.disable=Nesūtīt paziņojumus email_notifications.submit=Saglabāt sūtīšanas iestatījumus + [repo] new_repo_helper=Repozitorijs satur projekta visus failus, tai skaitā to izmaiņu vēsturi. Jau ir pieejams citur? Migrējiet repozitoriju. owner=Īpašnieks @@ -1709,7 +1709,6 @@ settings.event_pull_request_review_desc=Izmaiņu pieprasījums apstiprināts, no settings.event_pull_request_sync=Izmaiņu pieprasījums sinhronizēts settings.event_pull_request_sync_desc=Izmaiņu pieprasījums sinhronizēts. settings.branch_filter=Atzaru filtrs -settings.branch_filter_desc=Atzaru ierobežojumi izmaiņu iesūtīšanas, zaru izveidošanas vai dzēšanas notikumien, izmantojot, glob izteiksmi. Ja norādīts tukšs vai *, notikumi uz visiem zariem tiks nosūtīti. Skatieties github.com/gobwas/glob pieraksta dokumentāciju. Piemērs: master, {master,release*}. settings.active=Aktīvs settings.active_helper=Informācija par notikumiem tiks nosūtīta uz šo tīmekļa āķa URL. settings.add_hook_success=Tīmekļa āķis tika pievienots. @@ -1779,7 +1778,6 @@ settings.dismiss_stale_approvals_desc=Kad tiek iesūtītas jaunas revīzijas, ka settings.require_signed_commits=Pieprasīt parakstītas revīzijas settings.require_signed_commits_desc=Noraidīt iesūtītās izmaiņas šim atzaram, ja tās nav parakstītas vai nav iespējams pārbaudīt. settings.protect_protected_file_patterns=Aizsargāto failu šablons (vairākus var norādīt atdalot ar semikolu '\;'): -settings.protect_protected_file_patterns_desc=Aizsargātie faili, ko nevar mainīt, pat ja lietotājam ir tiesības veidot jaunus, labot vai dzēst failus šajā atzarā. Vairākus šablons ir iespējams norādīt atdalot tos ar semikolu ('\;'). Sīkāka informācija par šabloniem pieejama github.com/gobwas/glob dokumentācijā. Piemēram, .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Iespējot aizsargāšanu settings.delete_protected_branch=Atspējot aizsargāšanu settings.update_protect_branch_success=Atzara aizsardzība atzaram '%s' tika saglabāta. diff --git a/options/locale/locale_ml-IN.ini b/options/locale/locale_ml-IN.ini index 9baa30fb92351..c92d1d811e763 100644 --- a/options/locale/locale_ml-IN.ini +++ b/options/locale/locale_ml-IN.ini @@ -250,7 +250,6 @@ openid_connect_desc=തിരഞ്ഞെടുത്ത ഓപ്പൺഐഡ openid_register_title=അംഗത്വമെടുക്കുക openid_register_desc=തിരഞ്ഞെടുത്ത ഓപ്പൺഐഡി യുആർഐ അജ്ഞാതമാണ്. ഇവിടെ നിന്നും ഒരു പുതിയ അക്കൗണ്ടുമായി ബന്ധപ്പെടുത്തുക. openid_signin_desc=നിങ്ങളുടെ OpenID URI നൽകുക. ഉദാഹരണത്തിന്: https://anne.me, bob.openid.org.cn അല്ലെങ്കിൽ gnusocial.net/carry. -disable_forgot_password_mail=അക്കൗണ്ട് വീണ്ടെടുക്കൽ പ്രവർത്തനരഹിതമാണ്. നിങ്ങളുടെ സൈറ്റ് അഡ്മിനിസ്ട്രേറ്ററുമായി ബന്ധപ്പെടുക. email_domain_blacklisted=നിങ്ങളുടെ ഇമെയിൽ വിലാസത്തിൽ രജിസ്റ്റർ ചെയ്യാൻ കഴിയില്ല. authorize_application=അപ്ലിക്കേഷനു് അംഗീകാരം നല്കുക authorize_application_created_by=%s സൃഷ്‌ടിച്ച അപ്ലിക്കേഷൻ ആണ്. @@ -572,6 +571,7 @@ email_notifications.onmention=ഇ-മെയിൽ പരാമര്‍ശിച email_notifications.disable=ഇമെയിൽ അറിയിപ്പുകൾ അപ്രാപ്തമാക്കുക email_notifications.submit=ഇ-മെയില്‍ മുൻഗണനകള്‍ + [repo] owner=ഉടമസ്ഥന്‍ repo_name=കലവറയുടെ പേരു് diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 52436a6bc1f21..8ead629b09823 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -295,7 +295,6 @@ openid_connect_desc=De gekozen OpenID-URI is onbekend. Koppel het aan een nieuw openid_register_title=Nieuw account aanmaken openid_register_desc=De gekozen OpenID-URI is onbekend. Koppel het aan een nieuw account hier. openid_signin_desc=Geef uw OpenID-URI. Bijvoorbeeld: https://anne.me, bob.openid.org.cn of gnusocial.net/carry. -disable_forgot_password_mail=Accountherstel is uitgeschakeld. Neem contact op met de beheerder van uw site. email_domain_blacklisted=Je kan je niet registreren met dit e-mailadres. authorize_application=Autoriseer applicatie authorize_redirect_notice=U wordt doorgestuurd naar %s als u deze toepassing toestaat. @@ -668,6 +667,7 @@ email_notifications.onmention=Alleen e-mail op vermelding email_notifications.disable=E-mailnotificaties uitschakelen email_notifications.submit=E-mailvoorkeur instellen + [repo] owner=Eigenaar owner_helper=Sommige organisaties kunnen niet worden weergegeven in de dropdown vanwege een limiet op het maximale aantal repositories. @@ -1625,7 +1625,6 @@ settings.event_pull_request_review_desc=Pull request goedgekeurd, afgewezen of r settings.event_pull_request_sync=Pull request gesynchroniseerd settings.event_pull_request_sync_desc=Pull request gesynchroniseerd. settings.branch_filter=Branch filter -settings.branch_filter_desc=Branch whitelist voor push, branch creatie en branch verwijdering events, gespecificeerd als glob patroon. Indien leeg of * worden events voor alle branches gerapporteerd. Zie github.com/gobwas/glob documentatie voor syntaxis. Voorbeelden: master, {master,release*}. settings.active=Actief settings.active_helper=Informatie over geactiveerde gebeurtenissen wordt naar deze webhook URL gestuurd. settings.add_hook_success=De webhook is toegevoegd. @@ -1694,7 +1693,6 @@ settings.dismiss_stale_approvals_desc=Wanneer nieuwe commits die de inhoud van h settings.require_signed_commits=Ondertekende Commits vereisen settings.require_signed_commits_desc=Weiger pushes naar deze branch als deze niet ondertekend of niet verifieerbaar is. settings.protect_protected_file_patterns=Beschermde bestandspatronen (gescheiden door een puntkomma '\;'): -settings.protect_protected_file_patterns_desc=Beschermde bestanden die niet direct gewijzigd mogen worden, zelfs als de gebruiker het recht heeft om bestanden in deze branch toe te voegen, te bewerken of te verwijderen. Meerdere patronen kunnen worden gescheiden met een puntkomma ('\;'). Zie github.com/gobwas/glob documentatie voor patroon syntaxis. Voorbeelden: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Bescherming aanzetten settings.delete_protected_branch=Bescherming uitzetten settings.update_protect_branch_success=Branch bescherming voor branch '%s' is bijgewerkt. diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index f036ada750eab..4478742f409a2 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -287,7 +287,6 @@ openid_connect_desc=Wybrany URI OpenID jest nieznany. Powiąż go z nowym kontem openid_register_title=Stwórz nowe konto openid_register_desc=Wybrany URI OpenID jest nieznany. Powiąż go z nowym kontem w tym miejscu. openid_signin_desc=Wpisz swój URI OpenID. Na przykład: https://anne.me, bob.openid.org.cn or gnusocial.net/carry. -disable_forgot_password_mail=Odzyskiwanie konta jest wyłączone. Skontaktuj się z administratorem strony. email_domain_blacklisted=Nie możesz zarejestrować się za pomocą tego adresu e-mail. authorize_application=Autoryzuj aplikację authorize_redirect_notice=Zostaniesz przekierowany(-a) do %s, jeśli autoryzujesz tę aplikację. @@ -633,6 +632,7 @@ email_notifications.onmention=Wyślij wiadomość e-mail wyłącznie przy wzmian email_notifications.disable=Wyłącz powiadomienia e-mail email_notifications.submit=Ustaw preferencje wiadomości e-mail + [repo] owner=Właściciel repo_name=Nazwa repozytorium @@ -1526,7 +1526,6 @@ settings.event_pull_request_review_desc=Pull request zatwierdzony, odrzucony lub settings.event_pull_request_sync=Pull Request Zsynchronizowany settings.event_pull_request_sync_desc=Pull request zsynchronizowany. settings.branch_filter=Filtr gałęzi -settings.branch_filter_desc=Biała lista gałęzi dla przepychania, tworzenia i usuwania gałęzi, określona jako wzorzec glob. Jeśli pusta, lub *, zdarzenia dla wszystkich gałęzi są wyświetlane. Sprawdź dokumentację github.com/gobwas/glob dla składni. Przykładowo: master, {master,release*}. settings.active=Aktywne settings.active_helper=Informacja o wywołanych wydarzeniach będzie przesłana do tego adresu URL Webhooka. settings.add_hook_success=Webhook został dodany. @@ -1595,7 +1594,6 @@ settings.dismiss_stale_approvals_desc=Kiedy nowe commity zmieniające zawartoś settings.require_signed_commits=Wymagaj podpisanych commitów settings.require_signed_commits_desc=Odrzucaj zmiany wypychane do tej gałęzi, jeśli nie są podpisane, lub są niemożliwe do zweryfikowania. settings.protect_protected_file_patterns=Wzory chronionych plików (rozdzielone średnikiem '\;'): -settings.protect_protected_file_patterns_desc=Chronione pliki, które nie mogą być zmienione bezpośrednio, nawet jeśli użytkownik ma uprawnienia do dodawania, edytowania lub usuwania plików w tej gałęzi. Wzorce można rozdzielić za pomocą średnika ('\;'). Zobacz dokumentację github.com/gobwas/glob dla składni wzorca. Przykłady: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Włącz ochronę settings.delete_protected_branch=Wyłącz ochronę settings.update_protect_branch_success=Ochrona gałęzi dla gałęzi "%s" została zaktualizowana. diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 4ca33f9899f40..14c1051597926 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -299,7 +299,6 @@ openid_connect_desc=O URI do OpenID escolhido é desconhecido. Associe-o com uma openid_register_title=Criar uma nova conta openid_register_desc=O URI do OpenID escolhido é desconhecido. Associe-o com uma nova conta aqui. openid_signin_desc=Digite a URI do seu OpenID. Por exemplo: https://anne.me, bob.openid.org.cn ou gnusocial.net/carry. -disable_forgot_password_mail=Recuperação de conta está desativada. Por favor, contate o administrador do servidor. email_domain_blacklisted=Você não pode se cadastrar com seu endereço de e-mail. authorize_application=Autorizar aplicativo authorize_redirect_notice=Você será redirecionado para %s se você autorizar este aplicativo. @@ -679,6 +678,7 @@ email_notifications.onmention=Somente e-mail com menção email_notifications.disable=Desabilitar notificações de e-mail email_notifications.submit=Atualizar preferências de e-mail + [repo] owner=Proprietário owner_helper=Algumas organizações podem não aparecer no menu devido a um limite de contagem dos repositórios. @@ -1560,7 +1560,6 @@ settings.event_issue_comment=Comentário da issue settings.event_issue_comment_desc=Comentário da issue criado, editado ou excluído. settings.event_pull_request=Pull request settings.branch_filter=Filtro de branch -settings.branch_filter_desc=Controle de permissão de push, eventos de criação e exclusão de branch, especificados como padrão glob. Se vazio ou *, eventos para todos os branches serão relatados. Veja github.com/gobwas/glob documentação para sintaxe. Exemplos: master, {master,release*}. settings.active=Ativo settings.active_helper=Informações sobre eventos disparados serão enviadas para esta URL do webhook. settings.add_hook_success=O webhook foi adicionado. diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index c5be95f6e9024..e14daa865f15d 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -83,6 +83,7 @@ add=Adicionar add_all=Adicionar tudo remove=Remover remove_all=Remover tudo +edit=Editar write=Escrever preview=Pré-visualizar @@ -300,7 +301,6 @@ openid_connect_desc=O URI do OpenID escolhido é desconhecido. Associe-o a uma n openid_register_title=Criar uma conta nova openid_register_desc=O URI do OpenID escolhido é desconhecido. Associe-o a uma nova conta aqui. openid_signin_desc=Insira o seu URI OpenID. Por exemplo: https://maria.me, manuel.openid.org.cn ou gnusocial.net/antonio. -disable_forgot_password_mail=A recuperação de conta está desabilitada. Entre em contacto com o administrador do sítio. email_domain_blacklisted=Não pode fazer um registo com o seu endereço de email. authorize_application=Autorizar aplicação authorize_redirect_notice=Irá ser reencaminhado para %s se autorizar esta aplicação. @@ -327,6 +327,11 @@ register_success=Inscrição bem sucedida +release.title=Título: %s +release.note=Nota: +release.downloads=Descargas: +release.download.zip=Código fonte (ZIP) +release.download.targz=Código fonte (TAR.GZ) repo.transfer.subject_to=%s gostaria de transferir "%s" para %s repo.transfer.subject_to_you=%s gostaria de transferir "%s" para si @@ -371,6 +376,7 @@ email_error=` não é um endereço de email válido.` url_error=` não é um URL válido.` include_error=` tem que conter o texto '%s'.` glob_pattern_error=` o padrão glob é inválido: %s.` +regex_pattern_error=` o padrão regex é inválido: %s.` unknown_error=Erro desconhecido: captcha_incorrect=O código CAPTCHA está errado. password_not_match=As senhas não coincidem. @@ -678,6 +684,14 @@ email_notifications.onmention=Enviar email somente quando mencionado(a) email_notifications.disable=Desabilitar notificações por email email_notifications.submit=Definir preferência do email +visibility=Visibilidade do utilizador +visibility.public=Pública +visibility.public_tooltip=Visível para todos os utilizadores +visibility.limited=Limitada +visibility.limited_tooltip=Visível apenas para utilizadores com sessão iniciada +visibility.private=Privada +visibility.private_tooltip=Visível apenas para membros da organização + [repo] new_repo_helper=Um repositório contém todos os ficheiros do projecto, incluindo o histórico das revisões. Já o tem noutro sítio? Migre o repositório. owner=Proprietário(a) @@ -827,6 +841,8 @@ migrate.git.description=Migrar ou espelhar dados git a partir de serviços Git migrate.gitlab.description=Migrar dados do GitLab.com ou de um servidor GitLab auto-hospedado. migrate.gitea.description=Migrar dados do Gitea.com ou de um servidor Gitea auto-hospedado. migrate.gogs.description=Migrar dados de notabug.com ou de outro servidor Gogs auto-hospedado. +migrate.migrating_issues=Migrando questões +migrate.migrating_pulls=Migrando pedidos de integração mirror_from=espelho de forked_from=derivado de @@ -1016,7 +1032,7 @@ issues.filter_milestones=Filtrar etapa issues.filter_projects=Filtrar projecto issues.filter_labels=Filtrar rótulo issues.filter_reviewers=Filtrar revisor -issues.new=Nova questão +issues.new=Questão nova issues.new.title_empty=O título não pode estar vazio issues.new.labels=Rótulos issues.new.add_labels_title=Aplicar rótulos @@ -1124,7 +1140,7 @@ issues.commented_at=`comentado %s` issues.delete_comment_confirm=Tem a certeza que quer eliminar este comentário? issues.context.copy_link=Copiar ligação issues.context.quote_reply=Citar resposta -issues.context.reference_issue=Criar nova questão referindo esta +issues.context.reference_issue=Criar uma nova questão referindo esta issues.context.edit=Editar issues.context.delete=Eliminar issues.no_content=Ainda não há conteúdo. @@ -1189,7 +1205,7 @@ issues.unlock_confirm=Desbloquear issues.lock.notice_1=- Outros utilizadores não podem adicionar novos comentários a esta questão. issues.lock.notice_2=- Você e outros colaboradores com acesso a este repositório ainda podem deixar comentários que outros possam ver. issues.lock.notice_3=- Pode sempre voltar a desbloquear esta questão no futuro. -issues.unlock.notice_1=- Todos poderiam comentar mais uma vez nesta questão. +issues.unlock.notice_1=- Todos poderão voltar a comentar nesta questão. issues.unlock.notice_2=- Pode sempre voltar a bloquear esta questão no futuro. issues.lock.reason=Motivo do bloqueio issues.lock.title=Bloquear diálogo sobre esta questão. @@ -1209,13 +1225,13 @@ issues.add_time=Adicionar tempo manualmente issues.del_time=Eliminar este registo de tempo issues.add_time_short=Adicionar tempo issues.add_time_cancel=Cancelar -issues.add_time_history=`adicionou o tempo gasto %s` +issues.add_time_history=`adicionou, %s, tempo gasto nesta questão` issues.del_time_history=`apagou o tempo gasto %s` issues.add_time_hours=Horas issues.add_time_minutes=Minutos issues.add_time_sum_to_small=Não foi inserido qualquer tempo. issues.time_spent_total=Total de tempo gasto -issues.time_spent_from_all_authors=`Tempo total gasto: %s` +issues.time_spent_from_all_authors=`Total de tempo gasto: %s` issues.due_date=Data de vencimento issues.invalid_due_date_format=O formato da data de vencimento tem que ser 'aaaa-mm-dd'. issues.error_modifying_due_date=Falhou a modificação da data de vencimento. @@ -1301,7 +1317,7 @@ pulls.nothing_to_compare=Estes ramos são iguais. Não há necessidade de criar pulls.nothing_to_compare_and_allow_empty_pr=Estes ramos são iguais. Este pedido de integração ficará vazio. pulls.has_pull_request=`Já existe um pedido de integração entre estes dois ramos: %[2]s#%[3]d` pulls.create=Criar um pedido de integração -pulls.title_desc=quer integrar %[1]d cometimentos de %[2] em %[3]s +pulls.title_desc=quer integrar %[1]d cometimento(s) de %[2]s em %[3]s pulls.merged_title_desc=integrou %[1]d cometimentos de %[2] em %[3]s %[4]s pulls.change_target_branch_at=`mudou o ramo de destino de %s para %s %s` pulls.tab_conversation=Diálogo @@ -1482,15 +1498,15 @@ activity.merged_prs_label=Integrados activity.opened_prs_label=Propostos activity.active_issues_count_1=%d questão vigente activity.active_issues_count_n=%d questões vigentes -activity.closed_issues_count_1=Questão encerrada -activity.closed_issues_count_n=Questões encerradas +activity.closed_issues_count_1=questão encerrada +activity.closed_issues_count_n=questões encerradas activity.title.issues_1=%d questão activity.title.issues_n=%d questões activity.title.issues_closed_from=%s resolvidas de %s activity.title.issues_created_by=%s criada por %s activity.closed_issue_label=Encerrada -activity.new_issues_count_1=Nova questão -activity.new_issues_count_n=Novas questões +activity.new_issues_count_1=questão nova +activity.new_issues_count_n=questões novas activity.new_issue_label=Em aberto activity.title.unresolved_conv_1=%d diálogo não resolvido activity.title.unresolved_conv_n=%d diálogos não resolvidos @@ -1736,7 +1752,7 @@ settings.event_pull_request_review_desc=Pedido de integração aprovado, rejeita settings.event_pull_request_sync=Pedido de integração sincronizado settings.event_pull_request_sync_desc=Pedido de integração sincronizado. settings.branch_filter=Filtro por ramo -settings.branch_filter_desc=Lista de permissões do ramo para eventos de envio e de criação e eliminação de ramos, especificada como um padrão glob. Se estiver em branco ou for *, serão reportados eventos para todos os ramos. Veja a documentação github.com/gobwas/glob para detalhes da sintaxe. Exemplos: trunk, {trunk,release*}. +settings.branch_filter_desc=Lista de permissões do ramo para eventos de envio e de criação e eliminação de ramos, especificada como um padrão glob. Se estiver em branco ou for *, serão reportados eventos para todos os ramos. Veja a documentação github.com/gobwas/glob para ver os detalhes da sintaxe. Exemplos: trunk, {trunk,release*}. settings.active=Em funcionamento settings.active_helper=Informação sobre eventos despoletados será enviada para o URL deste automatismo web. settings.add_hook_success=O automatismo web foi adicionado. @@ -1825,6 +1841,16 @@ settings.choose_branch=Escolha um ramo… settings.no_protected_branch=Não existem ramos protegidos. settings.edit_protected_branch=Editar settings.protected_branch_required_approvals_min=O número mínimo exigido de aprovações não pode ser negativo. +settings.tags=Etiquetas +settings.tags.protection=Proteger etiquetas +settings.tags.protection.pattern=Padrão das etiquetas +settings.tags.protection.allowed=Com permissão +settings.tags.protection.allowed.users=Utilizadores com permissão +settings.tags.protection.allowed.teams=Equipas com permissão +settings.tags.protection.allowed.noone=Ninguém +settings.tags.protection.create=Proteger etiqueta +settings.tags.protection.none=Não há etiquetas protegidas. +settings.tags.protection.pattern.description=Pode usar um só nome ou um padrão glob ou uma expressão regular para corresponder a várias etiquetas. Para mais informações leia o guia das etiquetas protegidas. settings.bot_token=Código do bot settings.chat_id=ID do diálogo settings.matrix.homeserver_url=URL do servidor caseiro @@ -1838,6 +1864,7 @@ settings.archive.success=O repositório foi arquivado com sucesso. settings.archive.error=Ocorreu um erro enquanto decorria o processo de arquivo do repositório. Veja os registo para obter mais detalhes. settings.archive.error_ismirror=Não pode arquivar um repositório que tenha sido espelhado. settings.archive.branchsettings_unavailable=As configurações dos ramos não estão disponíveis quando o repositório está arquivado. +settings.archive.tagsettings_unavailable=As configurações sobre etiquetas não estão disponíveis quando o repositório está arquivado. settings.unarchive.button=Desarquivar repositório settings.unarchive.header=Desarquivar este repositório settings.unarchive.text=Desarquivar o repositório irá restaurar a capacidade de receber cometimentos e envios, assim como novas questões e pedidos de integração. @@ -1950,6 +1977,7 @@ release.deletion_tag_desc=Esta etiqueta vai ser eliminada do repositório. O con release.deletion_tag_success=A etiqueta foi eliminada. release.tag_name_already_exist=Já existe um lançamento com esta etiqueta. release.tag_name_invalid=A etiqueta não é válida. +release.tag_name_protected=O nome da etiqueta está protegido. release.tag_already_exist=Este nome de etiqueta já existe. release.downloads=Descargas release.download_count=Descargas: %s @@ -2194,7 +2222,7 @@ dashboard.total_gc_time=Pausa total da recolha de lixo dashboard.total_gc_pause=Pausa total da recolha de lixo dashboard.last_gc_pause=Última pausa da recolha de lixo dashboard.gc_times=Tempos da recolha de lixo -dashboard.delete_old_actions=Eliminar todas as operações da base de dados +dashboard.delete_old_actions=Eliminar todas as operações antigas da base de dados dashboard.delete_old_actions.started=Foi iniciado o processo de eliminação de todas as operações antigas da base de dados. users.user_manage_panel=Gestão das contas de utilizadores diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 08738ab84b2d8..a813a64d03af7 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -300,7 +300,6 @@ openid_connect_desc=Выбранный OpenID URI неизвестен. Свяж openid_register_title=Создать новый аккаунт openid_register_desc=Выбранный OpenID URI неизвестен. Свяжите с новой учетной записью здесь. openid_signin_desc=Введите свой OpenID URI. Например: https://anne.me, bob.openid.org.cn или gnusocial.net/carry. -disable_forgot_password_mail=Восстановление аккаунта отключено. Пожалуйста, свяжитесь с администратором сайта. email_domain_blacklisted=С данным адресом электронной почты регистрация невозможна. authorize_application=Авторизация приложения authorize_redirect_notice=Вы будете перенаправлены на %s, если вы авторизуете это приложение. @@ -675,6 +674,7 @@ email_notifications.onmention=Посылать письмо на эл. почт email_notifications.disable=Отключить почтовые уведомления email_notifications.submit=Установить настройки электронной почты + [repo] new_repo_helper=Репозиторий содержит все файлы проекта, включая историю ревизии. Уже есть где-то еще? Мигрировать репозиторий. owner=Владелец @@ -1711,7 +1711,6 @@ settings.event_pull_request_review_desc=Запрос на слияние утв settings.event_pull_request_sync=Синхронизация Pull Request settings.event_pull_request_sync_desc=Запрос на слияние синхронизирован. settings.branch_filter=Фильтр веток -settings.branch_filter_desc=Белый список ветвей для событий Push, создания ветвей и удаления ветвей, указанных в виде глобуса. Если пусто или *, сообщается о событиях для всех филиалов. Смотрите github.com/gobwas/glob документацию по синтаксису. Примеры: master, {master,release*}. settings.active=Активный settings.active_helper=Информация о происходящих событиях будет отправляться на URL-адрес этого вебхука. settings.add_hook_success=Вебхук был добавлен. @@ -1781,7 +1780,6 @@ settings.dismiss_stale_approvals_desc=Когда новые коммиты, из settings.require_signed_commits=Требовать подписанные коммиты settings.require_signed_commits_desc=Отклонить push'ы в эту ветку, если они не подписаны или не проверены. settings.protect_protected_file_patterns=Защищённые шаблоны файлов (разделённые через '\;'): -settings.protect_protected_file_patterns_desc=Защищенные файлы, которые не могут быть изменены напрямую, даже если пользователь имеет право добавлять, редактировать или удалять файлы в этой ветке. Несколько шаблонов могут быть разделены точкой с запятой ('\;'). Смотрите github.com/gobwas/glob документацию для синтаксиса шаблонов. Например: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Включить защиту settings.delete_protected_branch=Отключить защиту settings.update_protect_branch_success=Настройки защиты ветки '%s' были успешно изменены. diff --git a/options/locale/locale_sr-SP.ini b/options/locale/locale_sr-SP.ini index 93a5f7a299f0f..48f5d7e7983fc 100644 --- a/options/locale/locale_sr-SP.ini +++ b/options/locale/locale_sr-SP.ini @@ -201,6 +201,7 @@ delete_account=Уклоните ваш налог confirm_delete_account=Потврдите брисање + [repo] owner=Власник repo_name=Име спремишта diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index e9f139566a11e..15f2c7890cfd7 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -289,7 +289,6 @@ openid_connect_desc=Vald OpenID URI är okänd. Associera den med ett nytt konto openid_register_title=Skapa nytt konto openid_register_desc=Vald OpenID URI är okänd. Associera den med ett nytt konto här. openid_signin_desc=Ange din OpenID URI. Exempelvis: https://anne.me, bob.openid.org.cn eller gnusocial.net/carry. -disable_forgot_password_mail=Kontoåterställning är inaktiverat. Vänligen kontakta din webbplatsadministratör. email_domain_blacklisted=Du kan inte registrera dig med din e-postadress. authorize_application=Godkänn applikation authorize_redirect_notice=Du kommer att omdirigeras till %s om du auktoriserar denna applikation. @@ -643,6 +642,7 @@ email_notifications.onmention=Endast e-post vid omnämnanden email_notifications.disable=Inaktivera notiser via mejl email_notifications.submit=Ställ in e-post inställningar + [repo] owner=Ägare repo_name=Utvecklingskatalogens namn diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index fc58691e96f31..c0ca1a7c86ce3 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -302,7 +302,6 @@ openid_connect_desc=Seçilen OpenID URI'si bilinmiyor. Burada yeni bir hesapla i openid_register_title=Yeni hesap oluştur openid_register_desc=Seçilen OpenID URI'si bilinmiyor. Burada yeni bir hesapla ilişkilendir. openid_signin_desc=OpenID URI'nızı girin. Örneğin: https://anne.me, bob.openid.org.cn veya gnusocial.net/carry. -disable_forgot_password_mail=Hesap kurtarma devre dışı. Lütfen site yöneticinizle iletişime geçin. email_domain_blacklisted=Bu e-posta adresinizle kayıt olamazsınız. authorize_application=Uygulamayı Yetkilendir authorize_redirect_notice=Bu uygulamayı yetkilendirirseniz %s adresine yönlendirileceksiniz. @@ -683,6 +682,7 @@ email_notifications.onmention=Sadece Bahsedilen E-posta email_notifications.disable=E-posta Bildirimlerini Devre Dışı Bırak email_notifications.submit=E-posta Tercihlerini Ayarla + [repo] new_repo_helper=Bir depo, revizyon geçmişi dahil tüm proje dosyalarını içerir. Zaten başka bir yerde mi var? Depoyu taşıyın. owner=Sahibi @@ -1755,7 +1755,6 @@ settings.event_pull_request_review_desc=Değişiklik isteği onaylandı, reddedi settings.event_pull_request_sync=Değişiklik İsteği Senkronize Edildi settings.event_pull_request_sync_desc=Değişiklik isteği senkronize edildi. settings.branch_filter=Dal filtresi -settings.branch_filter_desc=Glob deseni olarak belirtilen itme, dal oluşturma ve dal silme olayları için dal beyaz listesi. Boş veya * ise, tüm dallar için olaylar bildirilir. Sözdizimi için github.com/gobwas/glob belgelerine bakın. Örnekler: master, {master,release*}. settings.active=Etkin settings.active_helper=Tetiklenen olaylar hakkındaki bilgiler bu web isteği URL'sine gönderilir. settings.add_hook_success=Web isteği eklendi. @@ -1825,7 +1824,6 @@ settings.dismiss_stale_approvals_desc=Değişiklik isteğinin içeriğini deği settings.require_signed_commits=İmzalı İşleme Gerekli settings.require_signed_commits_desc=Reddetme, onlar imzasızsa veya doğrulanamazsa bu dala gönderir. settings.protect_protected_file_patterns=Korumalı dosya kalıpları (noktalı virgülle ayrılmış '\;'): -settings.protect_protected_file_patterns_desc=Kullanıcı bu dalda dosya ekleme, düzenleme veya silme haklarına sahip olsa bile doğrudan değiştirilmesine izin verilmeyen korumalı dosyalar. Birden çok desen noktalı virgül ('\;') kullanılarak ayrılabilir. Desen sözdizimi belgeleri için github.com/gobwas/glob adresine bakın. Örnekler: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Korumayı etkinleştir settings.delete_protected_branch=Korumayı devre dışı bırak settings.update_protect_branch_success='%s' dalı için dal koruması güncellendi. diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index d1392e87a5ded..cfdcb1dcef10f 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -287,7 +287,6 @@ openid_connect_desc=Вибраний OpenID URI невідомий. Пов'яж openid_register_title=Створити новий обліковий запис openid_register_desc=Вибраний OpenID URI невідомий. Пов'яжіть йогоз новим обліковим записом тут. openid_signin_desc=Введіть свій ідентифікатор OpenID. Наприклад: https://anne.me, bob.openid.org.cn або gnusocial.net/carry. -disable_forgot_password_mail=Відновлення облікового запису вимкнено. Зверніться до адміністратора сайту. email_domain_blacklisted=З вказаним email реєстрація неможлива. authorize_application=Авторизувати програму authorize_redirect_notice=Вас буде переадресовано до %s, якщо ви авторизуєте цю програму. @@ -633,6 +632,7 @@ email_notifications.onmention=Повідомлення email тільки кол email_notifications.disable=Вимкнути email сповіщення email_notifications.submit=Налаштувати параметри email + [repo] owner=Власник repo_name=Назва репозиторію @@ -1531,7 +1531,6 @@ settings.event_pull_request_review_desc=Коментар запиту до зл settings.event_pull_request_sync=Запит на злиття синхронізується settings.event_pull_request_sync_desc=Запит до злиття синхронізовано. settings.branch_filter=Фільтр гілок -settings.branch_filter_desc=Білий список повідомлень push гілок, створення гілок та видалення гілок, визначається як glob шаблон. Якщо пустий або *, повідомлення для вісіх гілок ввімкнено. Дівіться github.com/gobwas/glob документацію на синтаксис. Приклад: master, {master,release*}. settings.active=Активний settings.active_helper=Інформацію про викликані події буде надіслано за цією веб-хук URL-адресою. settings.add_hook_success=Веб-хук було додано. @@ -1601,7 +1600,6 @@ settings.dismiss_stale_approvals_desc=Коли нові коміти що змі settings.require_signed_commits=Потрібно підписані коміти settings.require_signed_commits_desc=Відхиляти push до цієї гілки, якщо вони не підписані або підпис неможливо перевірити. settings.protect_protected_file_patterns=Шаблони захищених файлів (розділені крапками з комою '\;'): -settings.protect_protected_file_patterns_desc=Захищені файли, які заборонено змінювати напряму, навіть якщо користувач має дозвіл додавати, редагувати чи видаляти файли у цій гілці. Декілька шаблонів можуть бути розділеними за допомогою крапки з комою ('\;'). github.com/gobwas/glob надає документацію щодо синтаксису шаблонів. Приклади: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Увімкнути захист settings.delete_protected_branch=Вимкнути захист settings.update_protect_branch_success=Налаштування захисту гілки '%s' були успішно змінені. diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 496d06e58af24..84a588f098fe6 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -302,7 +302,6 @@ openid_connect_desc=所选的 OpenID URI 未知。在这里关联一个新帐户 openid_register_title=创建新帐户 openid_register_desc=所选的 OpenID URI 未知。在这里关联一个新帐户。 openid_signin_desc=输入您的 OpenID URI。例如: https://anne.me、bob.openid.org.cn 或 gnusocial.net/carry。 -disable_forgot_password_mail=帐户恢复功能已被禁用。请与网站管理员联系。 email_domain_blacklisted=您不能使用您的电子邮件地址注册。 authorize_application=应用授权 authorize_redirect_notice=如果您授权此应用,您将会被重定向到 %s。 @@ -683,6 +682,7 @@ email_notifications.onmention=只在被提到时邮件通知 email_notifications.disable=停用邮件通知 email_notifications.submit=邮件通知设置 + [repo] new_repo_helper=仓库包含所有项目文件,包括修订历史。已经在别处有了吗? 迁移代码库 owner=拥有者 @@ -1763,7 +1763,6 @@ settings.event_pull_request_review_desc=合并请求被批准、拒绝或提出 settings.event_pull_request_sync=合并请求被同步 settings.event_pull_request_sync_desc=合并请求被同步。 settings.branch_filter=分支过滤 -settings.branch_filter_desc=推送、创建,删除分支事件白名单,支持匹配符。如果为空或者 *,所有分支的事件均被触发。语法参见 github.com/gobwas/glob 。示例: Master, {master,release*}。 settings.active=激活 settings.active_helper=触发事件的信息将发送到此 webhook 网址。 settings.add_hook_success=Web 钩子添加成功! @@ -1833,7 +1832,6 @@ settings.dismiss_stale_approvals_desc=当新的提交更改合并请求内容被 settings.require_signed_commits=需要签名提交 settings.require_signed_commits_desc=拒绝推送未签名或无法验证的提交到分支 settings.protect_protected_file_patterns=受保护的文件模式(使用分号分隔) -settings.protect_protected_file_patterns_desc=即使用户有权添加、编辑或删除此分支中的文件,不允许直接更改受保护文件。 可以使用分号 ('\;') 分隔多个模式。 见 github.com/gobwas/glob 文档以获取图案语法。例如: .drone.yml, /docs/**/*.txt settings.add_protected_branch=启用保护 settings.delete_protected_branch=禁用保护 settings.update_protect_branch_success=分支 "%s" 的分支保护已更新。 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index 8d514c7962a9a..a1717aa4f57e4 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -250,6 +250,7 @@ delete_account=刪除當前帳戶 confirm_delete_account=確認刪除帳戶 + [repo] owner=擁有者 repo_name=儲存庫名稱 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index da0f2192a7f6d..895faeb88e0c2 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -83,6 +83,7 @@ add=增加 add_all=全部增加 remove=移除 remove_all=全部移除 +edit=編輯 write=撰寫 preview=預覽 @@ -191,7 +192,7 @@ admin_password=管理員密碼 confirm_password=確認密碼 admin_email=電子信箱 install_btn_confirm=安裝 Gitea -test_git_failed=無法識別 'git' 命令:%v +test_git_failed=無法識別「git」命令:%v sqlite3_not_available=您目前的版本不支援 SQLite3,請從 %s 下載官方的預先編譯版本(不是 gobuild 版本)。 invalid_db_setting=資料庫設定不正確: %v invalid_repo_path=儲存庫根目錄設定不正確:%v @@ -249,7 +250,7 @@ repo_no_results=沒有找到符合的儲存庫。 user_no_results=沒有找到符合的使用者。 org_no_results=沒有找到符合的組織。 code_no_results=找不到符合您關鍵字的原始碼。 -code_search_results=搜尋結果:'%s' +code_search_results=「%s」的搜尋結果 code_last_indexed_at=最後索引 %s [auth] @@ -302,7 +303,8 @@ openid_connect_desc=所選的 OpenID URI 未知。在這裡連結一個新帳戶 openid_register_title=建立新帳戶 openid_register_desc=所選的 OpenID URI 未知。在這裡連結一個新帳戶。 openid_signin_desc=輸入您的 OpenID URI。例如: https://anne.me、bob.openid.org.cn 或 gnusocial.net/carry。 -disable_forgot_password_mail=已停用帳戶救援功能。請與網站管理員聯絡。 +disable_forgot_password_mail=由於未設定電子郵件功能,帳戶救援功能已被停用。請與網站管理員聯絡。 +disable_forgot_password_mail_admin=帳戶救援功能需要設定電子郵件功能才能使用。請設定電子郵件功能以啟用帳戶救援功能。 email_domain_blacklisted=您無法使用您的電子信箱註冊帳號。 authorize_application=授權應用程式 authorize_redirect_notice=如果您授權此應用程式,您將會被重新導向至 %s。 @@ -316,26 +318,64 @@ password_pwned=您選擇的密碼已被列於設定您的密碼。 reset_password=救援您的帳戶 +reset_password.title=%s,您已請求帳戶救援 +reset_password.text=請在 %s內點擊下列連結以救援您的帳戶: register_success=註冊成功 - +issue_assigned.pull=@%[1]s 將儲存庫 %[3]s 的合併請求 %[2]s 指派給您。 +issue_assigned.issue=@%[1]s 將儲存庫 %[3]s 的問題 %[2]s 指派給您。 + +issue.x_mentioned_you=@%s 提到了您: +issue.action.force_push=%[1]s 強制推送了 %[2]s 自 %[3]s 至 %[4]s。 +issue.action.push_1=@%[1]s 推送了 1 個提交到 %[2]s +issue.action.push_n=@%[1]s 推送了 %[3]d 個提交到 %[2]s +issue.action.close=@%[1]s 關閉了 #%[2]d。 +issue.action.reopen=@%[1]s 重新開放了 #%[2]d。 +issue.action.merge=@%[1]s 合併了 #%[2]d 到 %[3]s。 +issue.action.approve=@%[1]s 核可了此合併請求。 +issue.action.reject=@%[1]s 請求更改此合併請求。 +issue.action.review=@%[1]s 在此合併請求上留言。 +issue.action.review_dismissed=@%[1]s 取消了 %[2]s 對此合併請求的上一個審核。 +issue.action.ready_for_review=@%[1]s 標記了此合併請求為準備好供審核。 +issue.action.new=@%[1]s 建立了 #%[2]d。 +issue.in_tree_path=在 %s 中: release.new.subject=%[2]s 中的 %[1]s 發佈了 +release.new.text=@%[1]s 於 %[3]s 發佈了 %[2]s +release.title=標題:%s +release.note=說明: +release.downloads=下載: +release.download.zip=原始碼(ZIP) +release.download.targz=原始碼(TAR.GZ) repo.transfer.subject_to=%s 想要把「%s」轉移給 %s repo.transfer.subject_to_you=%s 想要把「%s」轉移給您 repo.transfer.to_you=您 +repo.transfer.body=請造訪 %s 以接受或拒絕轉移,您也可以忽略它。 repo.collaborator.added.subject=%s 把您加入到 %s +repo.collaborator.added.text=您已被新增為儲存庫的協作者: [modal] yes=確認操作 @@ -345,7 +385,7 @@ modify=更新 [form] UserName=帳號 RepoName=儲存庫名稱 -Email=郵箱地址 +Email=電子信箱 Password=密碼 Retype=再次輸入密碼 SSHTitle=SSH 金鑰名稱 @@ -353,7 +393,7 @@ HttpsUrl=HTTPS URL 地址 PayloadUrl=推送地址 TeamName=團隊名稱 AuthName=認證名稱 -AdminEmail=管理員郵箱 +AdminEmail=管理員電子信箱 NewBranchName=新的分支名稱 CommitSummary=提交摘要 @@ -365,17 +405,18 @@ Content=內容 SSPISeparatorReplacement=分隔符 SSPIDefaultLanguage=預設語言 -require_error=不能為空。 +require_error=` 不能為空。` alpha_dash_error=`應該只包含英文字母、數字、破折號 ("-")、和底線 ("_") 字元。` alpha_dash_dot_error=`應該只包含英文字母、數字、破折號 ("-")、下底線("_")和小數點 (".") 字元。` git_ref_name_error=` 必須是格式正確的 Git 參考名稱。` -size_error=長度必須為 %s。 -min_size_error=長度最小為 %s 個字符。 -max_size_error=長度最大為 %s 個字符。 -email_error=不是一個有效的郵箱地址。 -url_error=不是一個有效的 URL。 -include_error=必須包含子字符串 '%s'。 -glob_pattern_error=` glob 比對模式無效: %s.` +size_error=` 長度必須為 %s。` +min_size_error=` 長度最小為 %s 個字元。` +max_size_error=` 長度最大為 %s 個字元。` +email_error=` 是無效的電子信箱。` +url_error=` 是無效的 URL。` +include_error=` 必須包含子字串「%s」。 +glob_pattern_error=` glob 比對模式無效:%s.` +regex_pattern_error=` 正規表示式模式無效:%s.` unknown_error=未知錯誤: captcha_incorrect=驗證碼不正確。 password_not_match=密碼錯誤。 @@ -395,7 +436,7 @@ team_name_been_taken=團隊名稱已被使用。 team_no_units_error=請至少選擇一個儲存庫區域。 email_been_used=此電子信箱已被使用 email_invalid=此電子信箱無效。 -openid_been_used=OpenID 位址 '%s' 已被使用。 +openid_been_used=OpenID 位址「%s」已被使用。 username_password_incorrect=帳號或密碼不正確 password_complexity=密碼複雜度沒有通過以下的要求: password_lowercase_one=至少要有一個小寫字母 @@ -441,7 +482,7 @@ disabled_public_activity=這個使用者已對外隱藏動態 form.name_reserved=帳號「%s」是被保留的。 form.name_pattern_not_allowed=帳號不可包含字元「%s」。 -form.name_chars_not_allowed=使用者名稱 '%s' 包含無效字元。 +form.name_chars_not_allowed=使用者名稱「%s」包含無效字元。 [settings] profile=個人資料 @@ -520,7 +561,7 @@ email_deletion_success=該電子信箱已被刪除 theme_update_success=已更新佈景主題。 theme_update_error=選取的佈景主題不存在。 openid_deletion=移除 OpenID 位址 -openid_deletion_desc=從您的帳戶刪除此 OpenID 位址將會無法使用它進行登入。你確定要繼續嗎? +openid_deletion_desc=從您的帳戶刪除此 OpenID 位址將會無法使用它進行登入。是否繼續? openid_deletion_success=該 OpenID 已被刪除 add_new_email=新增電子信箱 add_new_openid=新增 OpenID URI @@ -607,7 +648,7 @@ manage_oauth2_applications=管理 OAuth2 應用程式 edit_oauth2_application=編輯 OAuth2 應用程式 oauth2_applications_desc=OAuth2 應用程式讓您的第三方應用程式安全地驗證此 Gitea 中的使用者。 remove_oauth2_application=刪除 OAuth2 應用程式 -remove_oauth2_application_desc=刪除 OAuth2 應用程式將會撤銷所有已簽署的 access token 存取權。繼續嗎? +remove_oauth2_application_desc=刪除 OAuth2 應用程式將會撤銷所有已簽署的 Access Token 存取權。是否繼續? remove_oauth2_application_success=已刪除應用程式。 create_oauth2_application=新增 OAuth2 應用程式 create_oauth2_application_button=建立應用程式 @@ -626,7 +667,7 @@ oauth2_regenerate_secret_hint=遺失您的密鑰? oauth2_client_secret_hint=請備份您的祕鑰。祕鑰在您離開這個頁面後將不會再顯示。 oauth2_application_edit=編輯 oauth2_application_create_description=OAuth2 應用程式讓您的第三方應用程式可以存取此 Gitea 上的帳戶。 -oauth2_application_remove_description=刪除 OAuth2 應用會拒絕它存取此 Gitea 上已授權的帳戶。繼續嗎? +oauth2_application_remove_description=刪除 OAuth2 應用會拒絕它存取此 Gitea 上已授權的帳戶。是否繼續? authorized_oauth2_applications=已授權的 OAuth2 應用程式 authorized_oauth2_applications_description=您已授權給這些第三方應用程式存取您個人 Gitea 帳戶。請對不再需要的應用程式撤銷存取權。 @@ -659,7 +700,7 @@ u2f_register_key=新增安全密鑰 u2f_nickname=暱稱 u2f_press_button=按下安全密鑰上的密碼進行註冊。 u2f_delete_key=移除安全密鑰 -u2f_delete_key_desc=如果刪除安全金鑰,將不能再使用它登入。確定要刪除嗎? +u2f_delete_key_desc=如果刪除安全金鑰,將不能再使用它登入。是否繼續? manage_account_links=管理已連結的帳戶 manage_account_links_desc=這些外部帳戶已連結到您的 Gitea 帳戶。 @@ -683,6 +724,14 @@ email_notifications.onmention=只在被提到時傳送郵件通知 email_notifications.disable=關閉郵件通知 email_notifications.submit=套用郵件偏好設定 +visibility=使用者瀏覽權限 +visibility.public=公開 +visibility.public_tooltip=對所有人公開 +visibility.limited=受限 +visibility.limited_tooltip=只有登入的使用者才能看到 +visibility.private=私人 +visibility.private_tooltip=只有組織成員才能看到 + [repo] new_repo_helper=儲存庫包含所有專案檔案,包含修訂歷史。已經存放於別處了嗎?遷移儲存庫。 owner=擁有者 @@ -760,6 +809,7 @@ delete_preexisting_label=刪除 delete_preexisting=刪除既有的檔案 delete_preexisting_content=刪除 %s 中的檔案 delete_preexisting_success=刪除 %s 中未接管的檔案 +blame_prior=檢視此變更前的 Blame transfer.accept=同意轉移 transfer.accept_desc=轉移到「%s」 @@ -793,8 +843,8 @@ archive.pull.nocomment=此存儲庫已封存,您不能在合併請求上留言 form.reach_limit_of_creation_1=您已經達到了您儲存庫的數量上限 (%d 個)。 form.reach_limit_of_creation_n=您已經達到了您儲存庫的數量上限 (%d 個)。 -form.name_reserved=儲存庫名稱 '%s' 是預留的。 -form.name_pattern_not_allowed=儲存庫名稱無法使用 "%s"。 +form.name_reserved=儲存庫名稱「%s」是被保留的。 +form.name_pattern_not_allowed=儲存庫名稱不可包含字元「%s」。 need_auth=授權 migrate_options=遷移選項 @@ -900,7 +950,7 @@ file_view_raw=查看原始文件 file_permalink=永久連結 file_too_large=檔案太大,無法顯示。 video_not_supported_in_browser=您的瀏覽器不支援使用 HTML5 播放影片。 -audio_not_supported_in_browser=您的瀏覽器不支援 HTML5 'audio' 標籤 +audio_not_supported_in_browser=您的瀏覽器不支援 HTML5 的「audio」標籤 stored_lfs=已使用 Git LFS 儲存 symbolic_link=符號連結 commit_graph=提交線圖 @@ -933,9 +983,9 @@ editor.cancel_lower=取消 editor.commit_signed_changes=提交簽署過的變更 editor.commit_changes=提交變更 editor.add_tmpl=新增「」 -editor.add=新增 '%s' -editor.update=更新 '%s' -editor.delete=刪除 '%s' +editor.add=新增「%s」 +editor.update=更新「%s」 +editor.delete=刪除「%s」 editor.commit_message_desc=(選填)加入詳細說明... editor.signoff_desc=在提交訊息底部加入提交者的「Signed-off-by」資訊。 editor.commit_directly_to_this_branch=直接提交到 %s 分支。 @@ -947,7 +997,7 @@ editor.cancel=取消 editor.filename_cannot_be_empty=檔案名稱不能為空。 editor.filename_is_invalid=檔名無效:%s editor.branch_does_not_exist=此儲存庫沒有名為「%s」的分支。 -editor.branch_already_exists='%s' 已存在於此存儲庫。 +editor.branch_already_exists=此儲存庫已有名為「%s」的分支。 editor.directory_is_a_file=目錄名稱「%s」已被此儲存庫的檔案使用。 editor.file_is_a_symlink=「%s」是符號連結。無法在網頁編輯器中修改符號連結。 editor.filename_is_a_directory=檔案名稱「%s」已被此儲存庫的目錄使用。 @@ -964,9 +1014,9 @@ editor.push_rejected_no_message=該變更被伺服器拒絕但未提供其它資 editor.push_rejected=該變更被伺服器拒絕但。請檢查 Githook。 editor.push_rejected_summary=完整的拒絕訊息: editor.add_subdir=加入目錄 -editor.unable_to_upload_files=上傳檔案失敗到 '%s', 錯誤訊息: %v +editor.unable_to_upload_files=上傳檔案到「%s」時失敗,錯誤訊息:%v editor.upload_file_is_locked=檔案「%s」已被 %s 鎖定 -editor.upload_files_to_dir=上傳檔案到 '%s' +editor.upload_files_to_dir=上傳檔案到「%s」 editor.cannot_commit_to_protected_branch=無法提交到受保護的分支「%s」。 editor.no_commit_to_branch=無法直接提交到分支因為: editor.user_no_push_to_branch=使用者無法推送到分支 @@ -1000,14 +1050,14 @@ projects.create=建立專案 projects.title=標題 projects.new=新增專案 projects.new_subheader=在同一個地方協調、追蹤和更新您的工作,使專案保持透明並按計畫進行。 -projects.create_success=已建立專案 '%s'。 +projects.create_success=已建立專案「%s」。 projects.deletion=刪除專案 projects.deletion_desc=刪除專案會從所有相關的問題移除它。是否繼續? projects.deletion_success=專案已被刪除。 projects.edit=編輯專案 projects.edit_subheader=專案可用來組織問題和追蹤進度。 projects.modify=更新專案 -projects.edit_success=專案 '%s' 已被更新。 +projects.edit_success=已更新專案「%s」。 projects.type.none=無 projects.type.basic_kanban=基本看板 projects.type.bug_triage=Bug 檢傷分類 @@ -1022,7 +1072,7 @@ projects.board.new=新增看板 projects.board.set_default=設為預設 projects.board.set_default_desc=將此看板設定為未分類問題及合併請求的預設看板 projects.board.delete=刪除看板 -projects.board.deletion_desc=刪除專案看板會將相關的問題移動到 '未分類'。是否繼續? +projects.board.deletion_desc=刪除專案看板會將所有相關的問題移動到「未分類」,是否繼續? projects.open=開啟 projects.close=關閉 @@ -1070,7 +1120,7 @@ issues.label_templates.title=載入一組預定義的標籤 issues.label_templates.info=沒有任何標籤。點擊「新增標籤」按鈕或使用預定義的標籤集。 issues.label_templates.helper=選擇一個標籤集 issues.label_templates.use=使用標籤集 -issues.label_templates.fail_to_load_file=載入標籤範本檔案 '%s' 失敗: %v +issues.label_templates.fail_to_load_file=載入標籤範本檔「%s」失敗:%v issues.add_label=加入了 %s 標籤 %s issues.add_labels=加入了 %s 標籤 %s issues.remove_label=移除了 %s 標籤 %s @@ -1093,7 +1143,7 @@ issues.delete_branch_at=`刪除分支 %s %s` issues.open_tab=%d 個開放中 issues.close_tab=%d 個已關閉 issues.filter_label=標籤 -issues.filter_label_exclude=`使用 alt + click/enter 來排除標籤`。 +issues.filter_label_exclude=`使用 alt + click/enter 來排除標籤` issues.filter_label_no_select=所有標籤 issues.filter_milestone=里程碑 issues.filter_milestone_no_select=所有里程碑 @@ -1183,15 +1233,15 @@ issues.label_edit=編輯 issues.label_delete=刪除 issues.label_modify=編輯標籤 issues.label_deletion=刪除標籤 -issues.label_deletion_desc=刪除標籤會將其從所有問題中刪除,繼續? +issues.label_deletion_desc=刪除標籤會將其從所有問題中刪除。是否繼續? issues.label_deletion_success=標籤已刪除。 issues.label.filter_sort.alphabetically=按字母順序排序 issues.label.filter_sort.reverse_alphabetically=按字母反向排序 issues.label.filter_sort.by_size=檔案由小到大 issues.label.filter_sort.reverse_by_size=檔案由大到小 issues.num_participants=%d 參與者 -issues.attachment.open_tab=`在新分頁中查看 '%s'` -issues.attachment.download=`點擊下載 '%s'` +issues.attachment.open_tab=`在新分頁中查看「%s」` +issues.attachment.download=`點擊下載「%s」` issues.subscribe=訂閱 issues.unsubscribe=取消訂閱 issues.lock=鎖定對話 @@ -1235,7 +1285,7 @@ issues.add_time_sum_to_small=沒有輸入時間。 issues.time_spent_total=總花費時間 issues.time_spent_from_all_authors=`總花費時間:%s` issues.due_date=截止日期 -issues.invalid_due_date_format=截止日期的格式錯誤,必須是 "yyyy-mm-dd" 的形式。 +issues.invalid_due_date_format=截止日期的格式必須為「yyyy-mm-dd」。 issues.error_modifying_due_date=無法修改截止日期。 issues.error_removing_due_date=無法移除截止日期。 issues.push_commit_1=加入了 %d 個提交 %s @@ -1319,7 +1369,7 @@ pulls.filter_branch=過濾分支 pulls.no_results=未找到結果 pulls.nothing_to_compare=這些分支的內容相同,無需建立合併請求。 pulls.nothing_to_compare_and_allow_empty_pr=這些分支的內容相同,此合併請求將會是空白的。 -pulls.has_pull_request=`已有相同的合併請求: %[2]s#%[3]d` +pulls.has_pull_request=`已有相同的合併請求:%[2]s#%[3]d` pulls.create=建立合併請求 pulls.title_desc=請求將 %[1]d 次程式碼提交從 %[2]s 合併至 %[3]s pulls.merged_title_desc=將 %[1]d 次代碼提交從 %[2]s 合併至 %[3]s %[4]s @@ -1423,13 +1473,13 @@ milestones.title=標題 milestones.desc=描述 milestones.due_date=截止日期(可選) milestones.clear=清除 -milestones.invalid_due_date_format=截止日期的格式必須為 'yyyy-mm-dd'。 -milestones.create_success=已建立里程碑 '%s'。 +milestones.invalid_due_date_format=截止日期的格式必須為「yyyy-mm-dd」。 +milestones.create_success=已建立里程碑「%s」。 milestones.edit=編輯里程碑 milestones.edit_subheader=里程碑可用來組織問題和追蹤進度。 milestones.cancel=取消 milestones.modify=更新里程碑 -milestones.edit_success=里程碑 '%s' 已更新。 +milestones.edit_success=已更新里程碑「%s」。 milestones.deletion=刪除里程碑 milestones.deletion_desc=刪除里程碑會從所有相關的問題移除它。是否繼續? milestones.deletion_success=里程碑已刪除 @@ -1539,7 +1589,7 @@ activity.git_stats_file_1=%d 個檔案 activity.git_stats_file_n=%d 個檔案 activity.git_stats_files_changed_1=已變更 activity.git_stats_files_changed_n=已變更 -activity.git_stats_additions=: +activity.git_stats_additions=: activity.git_stats_addition_1=新增 %d 行 activity.git_stats_addition_n=新增 %d 行 activity.git_stats_and_deletions=和 @@ -1763,7 +1813,7 @@ settings.event_pull_request_review_desc=核准、退回或提出審核留言。 settings.event_pull_request_sync=合併請求同步 settings.event_pull_request_sync_desc=合併請求同步。 settings.branch_filter=分支篩選 -settings.branch_filter_desc=推送、建立分支、刪除分支事件的白名單,請使用 glob 比對模式。如果留白或輸入*,所有分支的事件都會被回報。語法參見 github.com/gobwas/glob。範例:master, {master,release*}。 +settings.branch_filter_desc=推送、建立分支、刪除分支事件的白名單,請使用 glob 比對模式。如果留白或輸入*,所有分支的事件都會被回報。語法參見 github.com/gobwas/glob。範例:master, {master,release*}。 settings.active=啟用 settings.active_helper=觸發事件的資訊將會被送到此 Webhook URL。 settings.add_hook_success=Webhook 新增成功! @@ -1822,7 +1872,7 @@ settings.protect_merge_whitelist_teams=允許合併的團隊: settings.protect_check_status_contexts=啟用狀態檢查 settings.protect_check_status_contexts_desc=合併前必須先通過狀態檢查。選擇合併前必須通過的檢查。啟用時,必須先將提交推送到另一個分支,通過狀態檢查後再合併或直接推送到符合規則的分支。如果未選擇任何項目,最一個提交必將成功通過狀態檢查。 settings.protect_check_status_contexts_list=此儲存庫一週內曾進行過狀態檢查 -settings.protect_required_approvals=需要的核可數量: +settings.protect_required_approvals=需要的核可數量: settings.protect_required_approvals_desc=只有在獲得足夠數量的核可後才能進行合併。 settings.protect_approvals_whitelist_enabled=使用白名單控管審核人員與團隊 settings.protect_approvals_whitelist_enabled_desc=只有白名單內的使用者與團隊會被計入需要的核可數量。未使用白名單時,將計算任何有寫入權限之人的核可。 @@ -1833,11 +1883,11 @@ settings.dismiss_stale_approvals_desc=當新的提交有修改到合併請求的 settings.require_signed_commits=僅接受經簽署的提交 settings.require_signed_commits_desc=拒絕未經簽署或未經驗證的提交推送到此分支。 settings.protect_protected_file_patterns=受保護的檔案模式(以分號區隔「\;」): -settings.protect_protected_file_patterns_desc=即便您有權限新增、修改和刪除此分支的檔案,仍不允許直接修改受保護的檔案。可以用分號「\;」分隔多個模式。請於 github.com/gobwas/glob 文件查看模式格式。範例:.drone.yml, /docs/**/*.txt。 +settings.protect_protected_file_patterns_desc=即便使用者有權限新增、修改和刪除此分支的檔案,仍不允許直接修改受保護的檔案。可以用半形分號「\;」分隔多個模式。請於github.com/gobwas/glob 文件查看模式格式。範例:.drone.yml, /docs/**/*.txt。 settings.add_protected_branch=啟用保護 settings.delete_protected_branch=停用保護 -settings.update_protect_branch_success='%s' 的分支保護已被更新 -settings.remove_protected_branch_success='%s' 的分支保護已被停用 +settings.update_protect_branch_success=已更新「%s」的分支保護。 +settings.remove_protected_branch_success=已停用「%s」的分支保護。 settings.protected_branch_deletion=停用分支保護 settings.protected_branch_deletion_desc=停用分支保護將允許有寫入權限的使用者推送至該分支,是否繼續? settings.block_rejected_reviews=有退回的審核時阻擋合併 @@ -1852,6 +1902,16 @@ settings.choose_branch=選擇一個分支... settings.no_protected_branch=沒有受保護的分支。 settings.edit_protected_branch=編輯 settings.protected_branch_required_approvals_min=需要的核可數量不能為負數。 +settings.tags=標籤 +settings.tags.protection=標籤保護 +settings.tags.protection.pattern=標籤格式 +settings.tags.protection.allowed=允許的 +settings.tags.protection.allowed.users=允許的使用者 +settings.tags.protection.allowed.teams=允許的團隊 +settings.tags.protection.allowed.noone=無 +settings.tags.protection.create=保護標籤 +settings.tags.protection.none=沒有受保護的標籤。 +settings.tags.protection.pattern.description=您可以使用單一名稱、Glob 模式、正規表示式來配對多個標籤。在受保護的標籤指南閱讀更多內容。 settings.bot_token=Bot Token settings.chat_id=Chat ID settings.matrix.homeserver_url=Homeserver 網址 @@ -1865,6 +1925,7 @@ settings.archive.success=此儲存庫已被封存 settings.archive.error=嘗試封存儲存庫時發生錯誤。查看日誌檔以獲得更多資訊。 settings.archive.error_ismirror=無法封存鏡像儲存庫。 settings.archive.branchsettings_unavailable=已封存的儲存庫無法使用分支設定。 +settings.archive.tagsettings_unavailable=已封存的儲存庫無法使用標籤設定。 settings.unarchive.button=解除封存儲存庫 settings.unarchive.header=解除封存本儲存庫 settings.unarchive.text=取消封存此儲存庫將使它能再次接收提交、推送、新問題與合併請求。 @@ -1979,6 +2040,7 @@ release.deletion_tag_desc=即將從儲存庫移除此標籤。儲存庫內容和 release.deletion_tag_success=已刪除此標籤。 release.tag_name_already_exist=已經存在使用相同標籤的發佈版本。 release.tag_name_invalid=標籤名稱無效。 +release.tag_name_protected=標籤名稱已受保護。 release.tag_already_exist=此標籤名稱已存在。 release.downloads=下載附件 release.download_count=下載次數:%s @@ -1987,7 +2049,7 @@ release.add_tag=只建立標籤 branch.name=分支名稱 branch.search=搜尋分支 -branch.already_exists=分支名稱 ”%s“ 已經存在 +branch.already_exists=已存在名為「%s」的分支。 branch.delete_head=刪除 branch.delete=刪除分支「%s」 branch.delete_html=刪除分支 @@ -1996,18 +2058,18 @@ branch.deletion_success=分支「%s」已被刪除。 branch.deletion_failed=刪除分支「%s」失敗。 branch.delete_branch_has_new_commits=因為合併後已加入了新的提交,「%s」分支無法被刪除。 branch.create_branch=建立分支 %s -branch.create_from=從 '%s' -branch.create_success=已建立分支 '%s'。 -branch.branch_already_exists=分支 '%s' 已存在此儲存庫 +branch.create_from=從「%s」 +branch.create_success=已建立分支「%s」。 +branch.branch_already_exists=此儲存庫已有名為「%s」的分支。 branch.branch_name_conflict=分支名稱「%s」與現有分支「%s」衝突。 branch.tag_collision=無法建立「%s」分支,因為此儲存庫中已有同名的標籤。 -branch.deleted_by=刪除人: %s +branch.deleted_by=由 %s 刪除 branch.restore_success=已還原分支「%s」。 branch.restore_failed=還原分支 %s 失敗 branch.protected_deletion_failed=分支「%s」已被保護,不能刪除。 branch.default_deletion_failed=分支「%s」為預設分支,不能刪除。 branch.restore=還原分支「%s」 -branch.download=下載分支 '%s' +branch.download=下載分支「%s」 branch.included_desc=此分支是預設分支的一部分 branch.included=包含 branch.create_new_branch=從下列分支建立分支: @@ -2021,7 +2083,7 @@ tag.create_success=已建立標籤「%s」。 topic.manage_topics=管理主題 topic.done=完成 topic.count_prompt=您最多能選擇 25 個主題 -topic.format_prompt=主題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字。 +topic.format_prompt=主題必須以字母或數字為開頭,可包含連接號「-」且最長為 35 個字元。 error.csv.too_large=無法渲染此檔案,因為它太大了。 error.csv.unexpected=無法渲染此檔案,因為它包含了未預期的字元,於第 %d 行第 %d 列。 @@ -2049,8 +2111,8 @@ team_permission_desc=權限 team_unit_desc=允許存取的儲存庫區域 team_unit_disabled=(已停用) -form.name_reserved=組織名稱 '%s' 是被保留的。 -form.name_pattern_not_allowed=儲存庫名稱無法使用 "%s"。 +form.name_reserved=組織名稱「%s」是被保留的。 +form.name_pattern_not_allowed=儲存庫名稱不可包含字元「%s」。 form.create_org_not_allowed=此帳號禁止建立組織。 settings=組織設定 @@ -2062,9 +2124,9 @@ settings.permission=權限 settings.repoadminchangeteam=儲存庫管理者可增加與移除團隊權限 settings.visibility=瀏覽權限 settings.visibility.public=公開 -settings.visibility.limited=受限(只有登入的使用者才能看到) +settings.visibility.limited=受限(只有登入的使用者才能看到) settings.visibility.limited_shortname=受限 -settings.visibility.private=私有(只有組織成員才能看到) +settings.visibility.private=私有(只有組織成員才能看到) settings.visibility.private_shortname=私有 settings.update_settings=更新設定 @@ -2239,7 +2301,7 @@ users.created=建立時間 users.last_login=上次登入 users.never_login=從未登入 users.send_register_notify=寄送使用者註冊通知 -users.new_success=已建立新帳戶 '%s'。 +users.new_success=已建立新帳戶「%s」。 users.edit=編輯 users.auth_source=認證來源 users.local=本地 @@ -2346,7 +2408,7 @@ auths.smtp_auth=SMTP 驗證類型 auths.smtphost=SMTP 主機地址 auths.smtpport=SMTP 連接埠 auths.allowed_domains=域名白名單 -auths.allowed_domains_helper=留白以允許所有域名。以逗號 (',') 分隔多個域名。 +auths.allowed_domains_helper=留白以允許所有域名。以半形逗號「,」分隔多個域名。 auths.enable_tls=啟用 TLS 加密 auths.skip_tls_verify=忽略 TLS 驗證 auths.pam_service_name=PAM 服務名稱 @@ -2391,7 +2453,7 @@ auths.tip.yandex=建立新的應用程式,從「Yandex.Passport API」區塊 auths.tip.mastodon=輸入您欲認證的 Mastodon 執行個體的自訂網址(或使用預設值) auths.edit=修改認證來源 auths.activated=該認證來源已啟用 -auths.new_success=已增加認證'%s'。 +auths.new_success=已增加認證「%s」。 auths.update_success=已更新認證來源。 auths.update=更新認證來源 auths.delete=刪除認證來源 @@ -2487,8 +2549,8 @@ config.mailer_sendmail_args=Sendmail 參數 config.mailer_sendmail_timeout=Sendmail 逾時 config.test_email_placeholder=電子信箱 (例:test@example.com) config.send_test_mail=傳送測試郵件 -config.test_mail_failed=傳送測試郵件到 '%s' 時失敗:'%v" -config.test_mail_sent=測試郵件已發送到 '%s' +config.test_mail_failed=傳送測試郵件到「%s」時失敗:%v +config.test_mail_sent=測試郵件已傳送到「%s」。 config.oauth_config=OAuth 組態 config.oauth_enabled=啟用服務 diff --git a/public/img/emoji/codeberg.png b/public/img/emoji/codeberg.png new file mode 100644 index 0000000000000..b91613833a2ff Binary files /dev/null and b/public/img/emoji/codeberg.png differ diff --git a/public/img/emoji/git.png b/public/img/emoji/git.png new file mode 100644 index 0000000000000..00a6bcfca4a2c Binary files /dev/null and b/public/img/emoji/git.png differ diff --git a/public/img/emoji/github.png b/public/img/emoji/github.png new file mode 100644 index 0000000000000..88efc353e776b Binary files /dev/null and b/public/img/emoji/github.png differ diff --git a/public/img/emoji/gitlab.png b/public/img/emoji/gitlab.png new file mode 100644 index 0000000000000..55a0d2b70b9e2 Binary files /dev/null and b/public/img/emoji/gitlab.png differ diff --git a/public/img/emoji/gogs.png b/public/img/emoji/gogs.png new file mode 100644 index 0000000000000..6471a84dadbbe Binary files /dev/null and b/public/img/emoji/gogs.png differ diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 4bbe7f77ba2ea..6bc9b849b1fc9 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -66,6 +66,7 @@ func CreateUser(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" form := web.GetForm(ctx).(*api.CreateUserOption) + u := &models.User{ Name: form.Username, FullName: form.FullName, @@ -97,7 +98,15 @@ func CreateUser(ctx *context.APIContext) { ctx.Error(http.StatusBadRequest, "PasswordPwned", errors.New("PasswordPwned")) return } - if err := models.CreateUser(u); err != nil { + + var overwriteDefault *models.CreateUserOverwriteOptions + if form.Visibility != "" { + overwriteDefault = &models.CreateUserOverwriteOptions{ + Visibility: api.VisibilityModes[form.Visibility], + } + } + + if err := models.CreateUser(u, overwriteDefault); err != nil { if models.IsErrUserAlreadyExist(err) || models.IsErrEmailAlreadyUsed(err) || models.IsErrNameReserved(err) || @@ -209,6 +218,9 @@ func EditUser(ctx *context.APIContext) { if form.Active != nil { u.IsActive = *form.Active } + if len(form.Visibility) != 0 { + u.Visibility = api.VisibilityModes[form.Visibility] + } if form.Admin != nil { u.IsAdmin = *form.Admin } @@ -395,6 +407,7 @@ func GetAllUsers(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) users, maxResults, err := models.SearchUsers(&models.SearchUserOptions{ + Actor: ctx.User, Type: models.UserTypeIndividual, OrderBy: models.SearchOrderByAlphabetically, ListOptions: listOptions, diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index c6b4ff04dec9d..b4f14bf2d1e03 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -722,6 +722,7 @@ func Routes() *web.Route { m.Combo("").Get(reqAnyRepoReader(), repo.Get). Delete(reqToken(), reqOwner(), repo.Delete). Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), repo.Edit) + m.Post("/generate", reqToken(), reqRepoReader(models.UnitTypeCode), bind(api.GenerateRepoOption{}), repo.Generate) m.Post("/transfer", reqOwner(), bind(api.TransferRepoOption{}), repo.Transfer) m.Combo("/notifications"). Get(reqToken(), notify.ListRepoNotifications). @@ -905,6 +906,7 @@ func Routes() *web.Route { m.Get(".diff", repo.DownloadPullDiff) m.Get(".patch", repo.DownloadPullPatch) m.Post("/update", reqToken(), repo.UpdatePullRequest) + m.Get("/commits", repo.GetPullRequestCommits) m.Combo("/merge").Get(repo.IsPullRequestMerged). Post(reqToken(), mustNotBeArchived, bind(forms.MergePullRequestForm{}), repo.MergePullRequest) m.Group("/reviews", func() { diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index f4a634f4d56c0..5c16594f89d18 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -225,8 +225,8 @@ func Get(ctx *context.APIContext) { // "200": // "$ref": "#/responses/Organization" - if !models.HasOrgVisible(ctx.Org.Organization, ctx.User) { - ctx.NotFound("HasOrgVisible", nil) + if !models.HasOrgOrUserVisible(ctx.Org.Organization, ctx.User) { + ctx.NotFound("HasOrgOrUserVisible", nil) return } ctx.JSON(http.StatusOK, convert.ToOrganization(ctx.Org.Organization)) diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go index a16cca0f4e147..9a0fd1d0b6f17 100644 --- a/routers/api/v1/repo/commits.go +++ b/routers/api/v1/repo/commits.go @@ -143,8 +143,8 @@ func GetAllCommits(ctx *context.APIContext) { listOptions.Page = 1 } - if listOptions.PageSize > git.CommitsRangeSize { - listOptions.PageSize = git.CommitsRangeSize + if listOptions.PageSize > setting.Git.CommitsRangeSize { + listOptions.PageSize = setting.Git.CommitsRangeSize } sha := ctx.Query("sha") diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go index 5a0911544a052..da0a2c501c8a1 100644 --- a/routers/api/v1/repo/hook.go +++ b/routers/api/v1/repo/hook.go @@ -140,16 +140,17 @@ func TestHook(ctx *context.APIContext) { return } + commit := convert.ToPayloadCommit(ctx.Repo.Repository, ctx.Repo.Commit) + if err := webhook.PrepareWebhook(hook, ctx.Repo.Repository, models.HookEventPush, &api.PushPayload{ - Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch, - Before: ctx.Repo.Commit.ID.String(), - After: ctx.Repo.Commit.ID.String(), - Commits: []*api.PayloadCommit{ - convert.ToPayloadCommit(ctx.Repo.Repository, ctx.Repo.Commit), - }, - Repo: convert.ToRepo(ctx.Repo.Repository, models.AccessModeNone), - Pusher: convert.ToUserWithAccessMode(ctx.User, models.AccessModeNone), - Sender: convert.ToUserWithAccessMode(ctx.User, models.AccessModeNone), + Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch, + Before: ctx.Repo.Commit.ID.String(), + After: ctx.Repo.Commit.ID.String(), + Commits: []*api.PayloadCommit{commit}, + HeadCommit: commit, + Repo: convert.ToRepo(ctx.Repo.Repository, models.AccessModeNone), + Pusher: convert.ToUserWithAccessMode(ctx.User, models.AccessModeNone), + Sender: convert.ToUserWithAccessMode(ctx.User, models.AccessModeNone), }); err != nil { ctx.Error(http.StatusInternalServerError, "PrepareWebhook: ", err) return diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index eff998ee996a1..0c09a9a86b0ee 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -6,7 +6,9 @@ package repo import ( "fmt" + "math" "net/http" + "strconv" "strings" "time" @@ -1101,3 +1103,122 @@ func UpdatePullRequest(ctx *context.APIContext) { ctx.Status(http.StatusOK) } + +// GetPullRequestCommits gets all commits associated with a given PR +func GetPullRequestCommits(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/pulls/{index}/commits repository repoGetPullRequestCommits + // --- + // summary: Get commits for a pull request + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: index + // in: path + // description: index of the pull request to get + // type: integer + // format: int64 + // required: true + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results + // type: integer + // responses: + // "200": + // "$ref": "#/responses/CommitList" + // "404": + // "$ref": "#/responses/notFound" + + pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrPullRequestNotExist(err) { + ctx.NotFound() + } else { + ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err) + } + return + } + + if err := pr.LoadBaseRepo(); err != nil { + ctx.InternalServerError(err) + return + } + + var prInfo *git.CompareInfo + baseGitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath()) + if err != nil { + ctx.ServerError("OpenRepository", err) + return + } + defer baseGitRepo.Close() + if pr.HasMerged { + prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName()) + } else { + prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName()) + } + if err != nil { + ctx.ServerError("GetCompareInfo", err) + return + } + commits := prInfo.Commits + + listOptions := utils.GetListOptions(ctx) + + totalNumberOfCommits := commits.Len() + totalNumberOfPages := int(math.Ceil(float64(totalNumberOfCommits) / float64(listOptions.PageSize))) + + userCache := make(map[string]*models.User) + + start, end := listOptions.GetStartEnd() + + if end > totalNumberOfCommits { + end = totalNumberOfCommits + } + + apiCommits := make([]*api.Commit, end-start) + + i := 0 + addedCommitsCount := 0 + for commitPointer := commits.Front(); commitPointer != nil; commitPointer = commitPointer.Next() { + if i < start { + i++ + continue + } + if i >= end { + break + } + + commit := commitPointer.Value.(*git.Commit) + + // Create json struct + apiCommits[addedCommitsCount], err = convert.ToCommit(ctx.Repo.Repository, commit, userCache) + addedCommitsCount++ + if err != nil { + ctx.ServerError("toCommit", err) + return + } + i++ + } + + ctx.SetLinkHeader(int(totalNumberOfCommits), listOptions.PageSize) + + ctx.Header().Set("X-Page", strconv.Itoa(listOptions.Page)) + ctx.Header().Set("X-PerPage", strconv.Itoa(listOptions.PageSize)) + ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", totalNumberOfCommits)) + ctx.Header().Set("X-PageCount", strconv.Itoa(totalNumberOfPages)) + ctx.Header().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages)) + ctx.JSON(http.StatusOK, &apiCommits) +} diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 7a3160fa9937e..5d397191a6138 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -307,6 +307,115 @@ func Create(ctx *context.APIContext) { CreateUserRepo(ctx, ctx.User, *opt) } +// Generate Create a repository using a template +func Generate(ctx *context.APIContext) { + // swagger:operation POST /repos/{template_owner}/{template_repo}/generate repository generateRepo + // --- + // summary: Create a repository using a template + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: template_owner + // in: path + // description: name of the template repository owner + // type: string + // required: true + // - name: template_repo + // in: path + // description: name of the template repository + // type: string + // required: true + // - name: body + // in: body + // schema: + // "$ref": "#/definitions/GenerateRepoOption" + // responses: + // "201": + // "$ref": "#/responses/Repository" + // "403": + // "$ref": "#/responses/forbidden" + // "404": + // "$ref": "#/responses/notFound" + // "409": + // description: The repository with the same name already exists. + // "422": + // "$ref": "#/responses/validationError" + form := web.GetForm(ctx).(*api.GenerateRepoOption) + + if !ctx.Repo.Repository.IsTemplate { + ctx.Error(http.StatusUnprocessableEntity, "", "this is not a template repo") + return + } + + if ctx.User.IsOrganization() { + ctx.Error(http.StatusUnprocessableEntity, "", "not allowed creating repository for organization") + return + } + + opts := models.GenerateRepoOptions{ + Name: form.Name, + Description: form.Description, + Private: form.Private, + GitContent: form.GitContent, + Topics: form.Topics, + GitHooks: form.GitHooks, + Webhooks: form.Webhooks, + Avatar: form.Avatar, + IssueLabels: form.Labels, + } + + if !opts.IsValid() { + ctx.Error(http.StatusUnprocessableEntity, "", "must select at least one template item") + return + } + + ctxUser := ctx.User + var err error + if form.Owner != ctxUser.Name { + ctxUser, err = models.GetOrgByName(form.Owner) + if err != nil { + if models.IsErrOrgNotExist(err) { + ctx.JSON(http.StatusNotFound, map[string]interface{}{ + "error": "request owner `" + form.Name + "` is not exist", + }) + return + } + + ctx.Error(http.StatusInternalServerError, "GetOrgByName", err) + return + } + + if !ctx.User.IsAdmin { + canCreate, err := ctxUser.CanCreateOrgRepo(ctx.User.ID) + if err != nil { + ctx.ServerError("CanCreateOrgRepo", err) + return + } else if !canCreate { + ctx.Error(http.StatusForbidden, "", "Given user is not allowed to create repository in organization.") + return + } + } + } + + repo, err := repo_service.GenerateRepository(ctx.User, ctxUser, ctx.Repo.Repository, opts) + if err != nil { + if models.IsErrRepoAlreadyExist(err) { + ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.") + } else if models.IsErrNameReserved(err) || + models.IsErrNamePatternNotAllowed(err) { + ctx.Error(http.StatusUnprocessableEntity, "", err) + } else { + ctx.Error(http.StatusInternalServerError, "CreateRepository", err) + } + return + } + log.Trace("Repository generated [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name) + + ctx.JSON(http.StatusCreated, convert.ToRepo(repo, models.AccessModeOwner)) +} + // CreateOrgRepoDeprecated create one repository of the organization func CreateOrgRepoDeprecated(ctx *context.APIContext) { // swagger:operation POST /org/{org}/repos organization createOrgRepoDeprecated @@ -375,8 +484,8 @@ func CreateOrgRepo(ctx *context.APIContext) { return } - if !models.HasOrgVisible(org, ctx.User) { - ctx.NotFound("HasOrgVisible", nil) + if !models.HasOrgOrUserVisible(org, ctx.User) { + ctx.NotFound("HasOrgOrUserVisible", nil) return } diff --git a/routers/api/v1/settings/settings.go b/routers/api/v1/settings/settings.go index e6417e40748c0..ca2d28fb8bf25 100644 --- a/routers/api/v1/settings/settings.go +++ b/routers/api/v1/settings/settings.go @@ -25,6 +25,7 @@ func GetGeneralUISettings(ctx *context.APIContext) { ctx.JSON(http.StatusOK, api.GeneralUISettings{ DefaultTheme: setting.UI.DefaultTheme, AllowedReactions: setting.UI.Reactions, + CustomEmojis: setting.UI.CustomEmojis, }) } diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go index b5f34e86a3815..0ae96a9203543 100644 --- a/routers/api/v1/swagger/options.go +++ b/routers/api/v1/swagger/options.go @@ -87,6 +87,8 @@ type swaggerParameterBodies struct { TransferRepoOption api.TransferRepoOption // in:body CreateForkOption api.CreateForkOption + // in:body + GenerateRepoOption api.GenerateRepoOption // in:body CreateStatusOption api.CreateStatusOption diff --git a/routers/api/v1/user/helper.go b/routers/api/v1/user/helper.go index fcdac257edc8d..a3500e0ee6487 100644 --- a/routers/api/v1/user/helper.go +++ b/routers/api/v1/user/helper.go @@ -17,7 +17,7 @@ func GetUserByParamsName(ctx *context.APIContext, name string) *models.User { user, err := models.GetUserByName(username) if err != nil { if models.IsErrUserNotExist(err) { - if redirectUserID, err := models.LookupUserRedirect(username); err == nil { + if redirectUserID, err2 := models.LookupUserRedirect(username); err2 == nil { context.RedirectToUser(ctx.Context, username, redirectUserID) } else { ctx.NotFound("GetUserByName", err) diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go index 4adae532fdfcf..ac543d597d7e8 100644 --- a/routers/api/v1/user/user.go +++ b/routers/api/v1/user/user.go @@ -57,6 +57,7 @@ func Search(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) opts := &models.SearchUserOptions{ + Actor: ctx.User, Keyword: strings.Trim(ctx.Query("q"), " "), UID: ctx.QueryInt64("uid"), Type: models.UserTypeIndividual, @@ -102,10 +103,16 @@ func GetInfo(ctx *context.APIContext) { // "$ref": "#/responses/notFound" u := GetUserByParams(ctx) + if ctx.Written() { return } + if !u.IsVisibleToUser(ctx.User) { + // fake ErrUserNotExist error message to not leak information about existence + ctx.NotFound("GetUserByName", models.ErrUserNotExist{Name: ctx.Params(":username")}) + return + } ctx.JSON(http.StatusOK, convert.ToUser(u, ctx.User)) } diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index c7af40dcf056e..5f2be65a29d99 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -133,7 +133,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID BranchFilter: form.BranchFilter, }, IsActive: form.Active, - Type: models.HookTaskType(form.Type), + Type: models.HookType(form.Type), } if w.Type == models.SLACK { channel, ok := form.Config["channel"] diff --git a/routers/common/repo.go b/routers/common/repo.go index 22403da09765e..8d33fb07fbbd5 100644 --- a/routers/common/repo.go +++ b/routers/common/repo.go @@ -64,16 +64,26 @@ func ServeData(ctx *context.Context, name string, size int64, reader io.Reader) st := typesniffer.DetectContentType(buf) + mappedMimeType := "" + if setting.MimeTypeMap.Enabled { + fileExtension := strings.ToLower(filepath.Ext(name)) + mappedMimeType = setting.MimeTypeMap.Map[fileExtension] + } if st.IsText() || ctx.QueryBool("render") { cs, err := charset.DetectEncoding(buf) if err != nil { log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err) cs = "utf-8" } - ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs)) + if mappedMimeType == "" { + mappedMimeType = "text/plain" + } + ctx.Resp.Header().Set("Content-Type", mappedMimeType+"; charset="+strings.ToLower(cs)) } else { ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition") - + if mappedMimeType != "" { + ctx.Resp.Header().Set("Content-Type", mappedMimeType) + } if (st.IsImage() || st.IsPDF()) && (setting.UI.SVG.Enabled || !st.IsSvgImage()) { ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name)) if st.IsSvgImage() { @@ -83,12 +93,6 @@ func ServeData(ctx *context.Context, name string, size int64, reader io.Reader) } } else { ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name)) - if setting.MimeTypeMap.Enabled { - fileExtension := strings.ToLower(filepath.Ext(name)) - if mimetype, ok := setting.MimeTypeMap.Map[fileExtension]; ok { - ctx.Resp.Header().Set("Content-Type", mimetype) - } - } } } diff --git a/routers/init.go b/routers/init.go index e52e547517f0d..05dbe4bd664ec 100644 --- a/routers/init.go +++ b/routers/init.go @@ -69,11 +69,13 @@ func GlobalInit(ctx context.Context) { if err := git.Init(ctx); err != nil { log.Fatal("Git module init failed: %v", err) } - setting.CheckLFSVersion() - log.Trace("AppPath: %s", setting.AppPath) - log.Trace("AppWorkPath: %s", setting.AppWorkPath) - log.Trace("Custom path: %s", setting.CustomPath) - log.Trace("Log path: %s", setting.LogRootPath) + log.Info(git.VersionInfo()) + + git.CheckLFSVersion() + log.Info("AppPath: %s", setting.AppPath) + log.Info("AppWorkPath: %s", setting.AppWorkPath) + log.Info("Custom path: %s", setting.CustomPath) + log.Info("Log path: %s", setting.LogRootPath) log.Info("Run Mode: %s", strings.Title(setting.RunMode)) // Setup i18n diff --git a/routers/install/routes_test.go b/routers/install/routes_test.go new file mode 100644 index 0000000000000..35a66c1c47426 --- /dev/null +++ b/routers/install/routes_test.go @@ -0,0 +1,20 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package install + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRoutes(t *testing.T) { + routes := Routes() + assert.NotNil(t, routes) + assert.Len(t, routes.R.Routes(), 1) + assert.EqualValues(t, "/", routes.R.Routes()[0].Pattern) + assert.Nil(t, routes.R.Routes()[0].SubRoutes) + assert.Len(t, routes.R.Routes()[0].Handlers, 2) +} diff --git a/routers/install/setting.go b/routers/install/setting.go index 53d166ba1de7f..7b9b7bd8c225b 100644 --- a/routers/install/setting.go +++ b/routers/install/setting.go @@ -18,11 +18,11 @@ import ( func PreloadSettings(ctx context.Context) bool { setting.NewContext() if !setting.InstallLock { - log.Trace("AppPath: %s", setting.AppPath) - log.Trace("AppWorkPath: %s", setting.AppWorkPath) - log.Trace("Custom path: %s", setting.CustomPath) - log.Trace("Log path: %s", setting.LogRootPath) - log.Trace("Preparing to run install page") + log.Info("AppPath: %s", setting.AppPath) + log.Info("AppWorkPath: %s", setting.AppWorkPath) + log.Info("Custom path: %s", setting.CustomPath) + log.Info("Log path: %s", setting.LogRootPath) + log.Info("Preparing to run install page") translation.InitLocales() if setting.EnableSQLite3 { log.Info("SQLite3 Supported") diff --git a/routers/utils/utils_test.go b/routers/utils/utils_test.go index 78ab3d20ee4f4..bca5263311145 100644 --- a/routers/utils/utils_test.go +++ b/routers/utils/utils_test.go @@ -62,7 +62,41 @@ func TestIsExternalURL(t *testing.T) { "//try.gitea.io/test?param=false"), newTest(false, "/hey/hey/hey#3244"), + newTest(true, + "://missing protocol scheme"), } { assert.Equal(t, test.Expected, IsExternalURL(test.RawURL)) } } + +func TestSanitizeFlashErrorString(t *testing.T) { + tests := []struct { + name string + arg string + want string + }{ + { + name: "no error", + arg: "", + want: "", + }, + { + name: "normal error", + arg: "can not open file: \"abc.exe\"", + want: "can not open file: "abc.exe"", + }, + { + name: "line break error", + arg: "some error:\n\nawesome!", + want: "some error:

awesome!", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := SanitizeFlashErrorString(tt.arg); got != tt.want { + t.Errorf("SanitizeFlashErrorString() = '%v', want '%v'", got, tt.want) + } + }) + } +} diff --git a/routers/web/admin/orgs.go b/routers/web/admin/orgs.go index 618f945704492..a2b3ed1bcc0fe 100644 --- a/routers/web/admin/orgs.go +++ b/routers/web/admin/orgs.go @@ -25,7 +25,8 @@ func Organizations(ctx *context.Context) { ctx.Data["PageIsAdminOrganizations"] = true explore.RenderUserSearch(ctx, &models.SearchUserOptions{ - Type: models.UserTypeOrganization, + Actor: ctx.User, + Type: models.UserTypeOrganization, ListOptions: models.ListOptions{ PageSize: setting.UI.Admin.OrgPagingNum, }, diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 1b65795865fa7..e1903ab1dfafc 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -37,7 +37,8 @@ func Users(ctx *context.Context) { ctx.Data["PageIsAdminUsers"] = true explore.RenderUserSearch(ctx, &models.SearchUserOptions{ - Type: models.UserTypeIndividual, + Actor: ctx.User, + Type: models.UserTypeIndividual, ListOptions: models.ListOptions{ PageSize: setting.UI.Admin.UserPagingNum, }, @@ -50,6 +51,8 @@ func NewUser(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("admin.users.new_account") ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminUsers"] = true + ctx.Data["DefaultUserVisibilityMode"] = setting.Service.DefaultUserVisibilityMode + ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice() ctx.Data["login_type"] = "0-0" @@ -70,6 +73,7 @@ func NewUserPost(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("admin.users.new_account") ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminUsers"] = true + ctx.Data["DefaultUserVisibilityMode"] = setting.Service.DefaultUserVisibilityMode sources, err := models.LoginSources() if err != nil { @@ -126,7 +130,8 @@ func NewUserPost(ctx *context.Context) { } u.MustChangePassword = form.MustChangePassword } - if err := models.CreateUser(u); err != nil { + + if err := models.CreateUser(u, &models.CreateUserOverwriteOptions{Visibility: form.Visibility}); err != nil { switch { case models.IsErrUserAlreadyExist(err): ctx.Data["Err_UserName"] = true @@ -207,6 +212,7 @@ func EditUser(ctx *context.Context) { ctx.Data["PageIsAdminUsers"] = true ctx.Data["DisableRegularOrgCreation"] = setting.Admin.DisableRegularOrgCreation ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations + ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice() prepareUserInfo(ctx) if ctx.Written() { @@ -312,6 +318,8 @@ func EditUserPost(ctx *context.Context) { u.AllowImportLocal = form.AllowImportLocal u.AllowCreateOrganization = form.AllowCreateOrganization + u.Visibility = form.Visibility + // skip self Prohibit Login if ctx.User.ID == u.ID { u.ProhibitLogin = false diff --git a/routers/web/admin/users_test.go b/routers/web/admin/users_test.go index b19dcb886bde1..5ce20d8fa777c 100644 --- a/routers/web/admin/users_test.go +++ b/routers/web/admin/users_test.go @@ -8,6 +8,8 @@ import ( "testing" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/forms" @@ -54,7 +56,6 @@ func TestNewUserPost_MustChangePassword(t *testing.T) { } func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { - models.PrepareTestEnv(t) ctx := test.MockContext(t, "admin/users/new") @@ -92,7 +93,6 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { } func TestNewUserPost_InvalidEmail(t *testing.T) { - models.PrepareTestEnv(t) ctx := test.MockContext(t, "admin/users/new") @@ -121,3 +121,80 @@ func TestNewUserPost_InvalidEmail(t *testing.T) { assert.NotEmpty(t, ctx.Flash.ErrorMsg) } + +func TestNewUserPost_VisiblityDefaultPublic(t *testing.T) { + models.PrepareTestEnv(t) + ctx := test.MockContext(t, "admin/users/new") + + u := models.AssertExistsAndLoadBean(t, &models.User{ + IsAdmin: true, + ID: 2, + }).(*models.User) + + ctx.User = u + + username := "gitea" + email := "gitea@gitea.io" + + form := forms.AdminCreateUserForm{ + LoginType: "local", + LoginName: "local", + UserName: username, + Email: email, + Password: "abc123ABC!=$", + SendNotify: false, + MustChangePassword: false, + } + + web.SetForm(ctx, &form) + NewUserPost(ctx) + + assert.NotEmpty(t, ctx.Flash.SuccessMsg) + + u, err := models.GetUserByName(username) + + assert.NoError(t, err) + assert.Equal(t, username, u.Name) + assert.Equal(t, email, u.Email) + // As default user visibility + assert.Equal(t, setting.Service.DefaultUserVisibilityMode, u.Visibility) +} + +func TestNewUserPost_VisibilityPrivate(t *testing.T) { + models.PrepareTestEnv(t) + ctx := test.MockContext(t, "admin/users/new") + + u := models.AssertExistsAndLoadBean(t, &models.User{ + IsAdmin: true, + ID: 2, + }).(*models.User) + + ctx.User = u + + username := "gitea" + email := "gitea@gitea.io" + + form := forms.AdminCreateUserForm{ + LoginType: "local", + LoginName: "local", + UserName: username, + Email: email, + Password: "abc123ABC!=$", + SendNotify: false, + MustChangePassword: false, + Visibility: api.VisibleTypePrivate, + } + + web.SetForm(ctx, &form) + NewUserPost(ctx) + + assert.NotEmpty(t, ctx.Flash.SuccessMsg) + + u, err := models.GetUserByName(username) + + assert.NoError(t, err) + assert.Equal(t, username, u.Name) + assert.Equal(t, email, u.Email) + // As default user visibility + assert.True(t, u.Visibility.IsPrivate()) +} diff --git a/routers/web/org/home.go b/routers/web/org/home.go index ad14f18454447..aad0a2a90b336 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -30,8 +30,8 @@ func Home(ctx *context.Context) { org := ctx.Org.Organization - if !models.HasOrgVisible(org, ctx.User) { - ctx.NotFound("HasOrgVisible", nil) + if !models.HasOrgOrUserVisible(org, ctx.User) { + ctx.NotFound("HasOrgOrUserVisible", nil) return } diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 1a3e1dcb9c570..4ade9e9a93a5a 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -5,7 +5,6 @@ package repo import ( - "bytes" "container/list" "fmt" "html" @@ -18,7 +17,6 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/highlight" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" ) @@ -27,6 +25,20 @@ const ( tplBlame base.TplName = "repo/home" ) +type blameRow struct { + RowNumber int + Avatar gotemplate.HTML + RepoLink string + PartSha string + PreviousSha string + PreviousShaURL string + IsFirstCommit bool + CommitURL string + CommitMessage string + CommitSince gotemplate.HTML + Code gotemplate.HTML +} + // RefBlame render blame page func RefBlame(ctx *context.Context) { fileName := ctx.Repo.TreePath @@ -39,19 +51,6 @@ func RefBlame(ctx *context.Context) { repoName := ctx.Repo.Repository.Name commitID := ctx.Repo.CommitID - commit, err := ctx.Repo.GitRepo.GetCommit(commitID) - if err != nil { - if git.IsErrNotExist(err) { - ctx.NotFound("Repo.GitRepo.GetCommit", err) - } else { - ctx.ServerError("Repo.GitRepo.GetCommit", err) - } - return - } - if len(commitID) != 40 { - commitID = commit.ID.String() - } - branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL() treeLink := branchLink rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL() @@ -74,25 +73,6 @@ func RefBlame(ctx *context.Context) { } } - // Show latest commit info of repository in table header, - // or of directory if not in root directory. - latestCommit := ctx.Repo.Commit - if len(ctx.Repo.TreePath) > 0 { - latestCommit, err = ctx.Repo.Commit.GetCommitByPath(ctx.Repo.TreePath) - if err != nil { - ctx.ServerError("GetCommitByPath", err) - return - } - } - ctx.Data["LatestCommit"] = latestCommit - ctx.Data["LatestCommitVerification"] = models.ParseCommitWithSignature(latestCommit) - ctx.Data["LatestCommitUser"] = models.ValidateCommitWithEmail(latestCommit) - - statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, ctx.Repo.Commit.ID.String(), models.ListOptions{}) - if err != nil { - log.Error("GetLatestCommitStatus: %v", err) - } - // Get current entry user currently looking at. entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) if err != nil { @@ -102,9 +82,6 @@ func RefBlame(ctx *context.Context) { blob := entry.Blob() - ctx.Data["LatestCommitStatus"] = models.CalcCommitStatus(statuses) - ctx.Data["LatestCommitStatuses"] = statuses - ctx.Data["Paths"] = paths ctx.Data["TreeLink"] = treeLink ctx.Data["TreeNames"] = treeNames @@ -145,8 +122,33 @@ func RefBlame(ctx *context.Context) { blameParts = append(blameParts, *blamePart) } + // Get Topics of this repo + renderRepoTopics(ctx) + if ctx.Written() { + return + } + + commitNames, previousCommits := processBlameParts(ctx, blameParts) + if ctx.Written() { + return + } + + renderBlame(ctx, blameParts, commitNames, previousCommits) + + ctx.HTML(http.StatusOK, tplBlame) +} + +func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) (map[string]models.UserCommit, map[string]string) { + // store commit data by SHA to look up avatar info etc commitNames := make(map[string]models.UserCommit) + // previousCommits contains links from SHA to parent SHA, + // if parent also contains the current TreePath. + previousCommits := make(map[string]string) + // and as blameParts can reference the same commits multiple + // times, we cache the lookup work locally commits := list.New() + commitCache := map[string]*git.Commit{} + commitCache[ctx.Repo.Commit.ID.String()] = ctx.Repo.Commit for _, part := range blameParts { sha := part.Sha @@ -154,14 +156,38 @@ func RefBlame(ctx *context.Context) { continue } - commit, err := ctx.Repo.GitRepo.GetCommit(sha) - if err != nil { - if git.IsErrNotExist(err) { - ctx.NotFound("Repo.GitRepo.GetCommit", err) - } else { - ctx.ServerError("Repo.GitRepo.GetCommit", err) + // find the blamePart commit, to look up parent & email address for avatars + commit, ok := commitCache[sha] + var err error + if !ok { + commit, err = ctx.Repo.GitRepo.GetCommit(sha) + if err != nil { + if git.IsErrNotExist(err) { + ctx.NotFound("Repo.GitRepo.GetCommit", err) + } else { + ctx.ServerError("Repo.GitRepo.GetCommit", err) + } + return nil, nil + } + commitCache[sha] = commit + } + + // find parent commit + if commit.ParentCount() > 0 { + psha := commit.Parents[0] + previousCommit, ok := commitCache[psha.String()] + if !ok { + previousCommit, _ = commit.Parent(0) + if previousCommit != nil { + commitCache[psha.String()] = previousCommit + } + } + // only store parent commit ONCE, if it has the file + if previousCommit != nil { + if haz1, _ := previousCommit.HasFile(ctx.Repo.TreePath); haz1 { + previousCommits[commit.ID.String()] = previousCommit.ID.String() + } } - return } commits.PushBack(commit) @@ -169,46 +195,39 @@ func RefBlame(ctx *context.Context) { commitNames[commit.ID.String()] = models.UserCommit{} } + // populate commit email addresses to later look up avatars. commits = models.ValidateCommitsWithEmails(commits) - for e := commits.Front(); e != nil; e = e.Next() { c := e.Value.(models.UserCommit) - commitNames[c.ID.String()] = c } - // Get Topics of this repo - renderRepoTopics(ctx) - if ctx.Written() { - return - } - - renderBlame(ctx, blameParts, commitNames) - - ctx.HTML(http.StatusOK, tplBlame) + return commitNames, previousCommits } -func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames map[string]models.UserCommit) { +func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames map[string]models.UserCommit, previousCommits map[string]string) { repoLink := ctx.Repo.RepoLink var lines = make([]string, 0) - - var commitInfo bytes.Buffer - var lineNumbers bytes.Buffer - var codeLines bytes.Buffer + rows := make([]*blameRow, 0) var i = 0 - for pi, part := range blameParts { + var commitCnt = 0 + for _, part := range blameParts { for index, line := range part.Lines { i++ lines = append(lines, line) - var attr = "" - if len(part.Lines)-1 == index && len(blameParts)-1 != pi { - attr = " bottom-line" + br := &blameRow{ + RowNumber: i, } + commit := commitNames[part.Sha] + previousSha := previousCommits[part.Sha] if index == 0 { + // Count commit number + commitCnt++ + // User avatar image commitSince := timeutil.TimeSinceUnix(timeutil.TimeStamp(commit.Author.When.Unix()), ctx.Data["Lang"].(string)) @@ -219,16 +238,14 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m avatar = string(templates.AvatarByEmail(commit.Author.Email, commit.Author.Name, 18, "mr-3")) } - commitInfo.WriteString(fmt.Sprintf(`
%s
%s
`, attr, avatar, repoLink, part.Sha, html.EscapeString(commit.CommitMessage), commitSince)) - } else { - commitInfo.WriteString(fmt.Sprintf(`
`, attr)) - } - - //Line number - if len(part.Lines)-1 == index && len(blameParts)-1 != pi { - lineNumbers.WriteString(fmt.Sprintf(``, i, i)) - } else { - lineNumbers.WriteString(fmt.Sprintf(``, i, i)) + br.Avatar = gotemplate.HTML(avatar) + br.RepoLink = repoLink + br.PartSha = part.Sha + br.PreviousSha = previousSha + br.PreviousShaURL = fmt.Sprintf("%s/blame/commit/%s/%s", repoLink, previousSha, ctx.Repo.TreePath) + br.CommitURL = fmt.Sprintf("%s/commit/%s", repoLink, part.Sha) + br.CommitMessage = html.EscapeString(commit.CommitMessage) + br.CommitSince = commitSince } if i != len(lines)-1 { @@ -236,16 +253,12 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m } fileName := fmt.Sprintf("%v", ctx.Data["FileName"]) line = highlight.Code(fileName, line) - line = `` + line + `` - if len(part.Lines)-1 == index && len(blameParts)-1 != pi { - codeLines.WriteString(fmt.Sprintf(`
  • %s
  • `, i, i, line)) - } else { - codeLines.WriteString(fmt.Sprintf(`
  • %s
  • `, i, i, line)) - } + + br.Code = gotemplate.HTML(line) + rows = append(rows, br) } } - ctx.Data["BlameContent"] = gotemplate.HTML(codeLines.String()) - ctx.Data["BlameCommitInfo"] = gotemplate.HTML(commitInfo.String()) - ctx.Data["BlameLineNums"] = gotemplate.HTML(lineNumbers.String()) + ctx.Data["BlameRows"] = rows + ctx.Data["CommitCnt"] = commitCnt } diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 4625b1a272fc8..da72940144fef 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/repofiles" repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" @@ -62,8 +63,8 @@ func Branches(ctx *context.Context) { } limit := ctx.QueryInt("limit") - if limit <= 0 || limit > git.BranchesRangeSize { - limit = git.BranchesRangeSize + if limit <= 0 || limit > setting.Git.BranchesRangeSize { + limit = setting.Git.BranchesRangeSize } skip := (page - 1) * limit @@ -73,7 +74,7 @@ func Branches(ctx *context.Context) { return } ctx.Data["Branches"] = branches - pager := context.NewPagination(int(branchesCount), git.BranchesRangeSize, page, 5) + pager := context.NewPagination(int(branchesCount), setting.Git.BranchesRangeSize, page, 5) pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 3e6148bcbbc76..45ef22f498be2 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -63,7 +63,7 @@ func Commits(ctx *context.Context) { pageSize := ctx.QueryInt("limit") if pageSize <= 0 { - pageSize = git.CommitsRangeSize + pageSize = setting.Git.CommitsRangeSize } // Both `git log branchName` and `git log commitId` work. @@ -82,7 +82,7 @@ func Commits(ctx *context.Context) { ctx.Data["CommitCount"] = commitsCount ctx.Data["Branch"] = ctx.Repo.BranchName - pager := context.NewPagination(int(commitsCount), git.CommitsRangeSize, page, 5) + pager := context.NewPagination(int(commitsCount), setting.Git.CommitsRangeSize, page, 5) pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager @@ -250,7 +250,7 @@ func FileHistory(ctx *context.Context) { ctx.Data["CommitCount"] = commitsCount ctx.Data["Branch"] = branchName - pager := context.NewPagination(int(commitsCount), git.CommitsRangeSize, page, 5) + pager := context.NewPagination(int(commitsCount), setting.Git.CommitsRangeSize, page, 5) pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 74e2a29597724..90d06d11c1e1a 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -29,6 +29,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/typesniffer" ) @@ -624,6 +625,7 @@ func Home(ctx *context.Context) { ctx.Data["Repo"] = ctx.Repo ctx.Data["MigrateTask"] = task ctx.Data["CloneAddr"] = safeURL(cfg.CloneAddr) + ctx.Data["Failed"] = task.Status == structs.TaskStatusFailed ctx.HTML(http.StatusOK, tplMigrating) return } diff --git a/routers/web/repo/webhook.go b/routers/web/repo/webhook.go index fe16d249eb0c9..e8d86db51d7d1 100644 --- a/routers/web/repo/webhook.go +++ b/routers/web/repo/webhook.go @@ -239,7 +239,7 @@ func GogsHooksNewPost(ctx *context.Context) { } // newGogsWebhookPost response for creating gogs hook -func newGogsWebhookPost(ctx *context.Context, form forms.NewGogshookForm, kind models.HookTaskType) { +func newGogsWebhookPost(ctx *context.Context, form forms.NewGogshookForm, kind models.HookType) { ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksNew"] = true @@ -1085,28 +1085,30 @@ func TestWebhook(ctx *context.Context) { } apiUser := convert.ToUserWithAccessMode(ctx.User, models.AccessModeNone) - p := &api.PushPayload{ - Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch, - Before: commit.ID.String(), - After: commit.ID.String(), - Commits: []*api.PayloadCommit{ - { - ID: commit.ID.String(), - Message: commit.Message(), - URL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(), - Author: &api.PayloadUser{ - Name: commit.Author.Name, - Email: commit.Author.Email, - }, - Committer: &api.PayloadUser{ - Name: commit.Committer.Name, - Email: commit.Committer.Email, - }, - }, + + apiCommit := &api.PayloadCommit{ + ID: commit.ID.String(), + Message: commit.Message(), + URL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(), + Author: &api.PayloadUser{ + Name: commit.Author.Name, + Email: commit.Author.Email, + }, + Committer: &api.PayloadUser{ + Name: commit.Committer.Name, + Email: commit.Committer.Email, }, - Repo: convert.ToRepo(ctx.Repo.Repository, models.AccessModeNone), - Pusher: apiUser, - Sender: apiUser, + } + + p := &api.PushPayload{ + Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch, + Before: commit.ID.String(), + After: commit.ID.String(), + Commits: []*api.PayloadCommit{apiCommit}, + HeadCommit: apiCommit, + Repo: convert.ToRepo(ctx.Repo.Repository, models.AccessModeNone), + Pusher: apiUser, + Sender: apiUser, } if err := webhook.PrepareWebhook(w, ctx.Repo.Repository, models.HookEventPush, p); err != nil { ctx.Flash.Error("PrepareWebhook: " + err.Error()) diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index cceb8451e58f5..5271fe9b4ad99 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -316,7 +317,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) ctx.Data["Commits"] = commitsHistory - pager := context.NewPagination(int(commitsCount), git.CommitsRangeSize, page, 5) + pager := context.NewPagination(int(commitsCount), setting.Git.CommitsRangeSize, page, 5) pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager diff --git a/routers/web/user/auth.go b/routers/web/user/auth.go index 10608841b3fc7..1e909339a883c 100644 --- a/routers/web/user/auth.go +++ b/routers/web/user/auth.go @@ -1479,6 +1479,7 @@ func ForgotPasswd(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("auth.forgot_password_title") if setting.MailService == nil { + log.Warn(ctx.Tr("auth.disable_forgot_password_mail_admin")) ctx.Data["IsResetDisable"] = true ctx.HTML(http.StatusOK, tplForgotPassword) return diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 72d00666453e2..631ca2113512a 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -75,6 +75,17 @@ func Profile(ctx *context.Context) { return } + if ctxUser.IsOrganization() { + org.Home(ctx) + return + } + + // check view permissions + if !ctxUser.IsVisibleToUser(ctx.User) { + ctx.NotFound("user", fmt.Errorf(uname)) + return + } + // Show SSH keys. if isShowKeys { ShowSSHKeys(ctx, ctxUser.ID) @@ -87,11 +98,6 @@ func Profile(ctx *context.Context) { return } - if ctxUser.IsOrganization() { - org.Home(ctx) - return - } - // Show OpenID URIs openIDs, err := models.GetUserOpenIDs(ctxUser.ID) if err != nil { diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index 20042caca4f72..682f9205784e3 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -38,6 +38,7 @@ const ( func Profile(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsProfile"] = true + ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice() ctx.HTML(http.StatusOK, tplSettingsProfile) } @@ -114,6 +115,7 @@ func ProfilePost(ctx *context.Context) { } ctx.User.Description = form.Description ctx.User.KeepActivityPrivate = form.KeepActivityPrivate + ctx.User.Visibility = form.Visibility if err := models.UpdateUserSetting(ctx.User); err != nil { if _, ok := err.(models.ErrEmailAlreadyUsed); ok { ctx.Flash.Error(ctx.Tr("form.email_been_used")) diff --git a/services/forms/admin.go b/services/forms/admin.go index 2e6bbaf172019..5abef0550e39a 100644 --- a/services/forms/admin.go +++ b/services/forms/admin.go @@ -8,6 +8,7 @@ import ( "net/http" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web/middleware" "gitea.com/go-chi/binding" @@ -22,6 +23,7 @@ type AdminCreateUserForm struct { Password string `binding:"MaxSize(255)"` SendNotify bool MustChangePassword bool + Visibility structs.VisibleType } // Validate validates form fields @@ -49,6 +51,7 @@ type AdminEditUserForm struct { AllowCreateOrganization bool ProhibitLogin bool Reset2FA bool `form:"reset_2fa"` + Visibility structs.VisibleType } // Validate validates form fields diff --git a/services/forms/user_form.go b/services/forms/user_form.go index 2c065dc5116a8..439ddfc7c64cd 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web/middleware" "gitea.com/go-chi/binding" @@ -226,10 +227,11 @@ type UpdateProfileForm struct { Name string `binding:"AlphaDashDot;MaxSize(40)"` FullName string `binding:"MaxSize(100)"` KeepEmailPrivate bool - Website string `binding:"ValidUrl;MaxSize(255)"` + Website string `binding:"ValidSiteUrl;MaxSize(255)"` Location string `binding:"MaxSize(50)"` Language string Description string `binding:"MaxSize(255)"` + Visibility structs.VisibleType KeepActivityPrivate bool } diff --git a/services/repository/push.go b/services/repository/push.go index f031073b2e0e0..26df6b8e45e66 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -95,7 +95,6 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { if opts.IsNewRef() && opts.IsDelRef() { return fmt.Errorf("Old and new revisions are both %s", git.EmptySHA) } - var commits = &repo_module.PushCommits{} if opts.IsTag() { // If is tag reference if pusher == nil || pusher.ID != opts.PusherID { var err error @@ -192,17 +191,19 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } } - commits = repo_module.ListToPushCommits(l) + commits := repo_module.ListToPushCommits(l) + commits.HeadCommit = repo_module.CommitToPushCommit(newCommit) + + if err := repofiles.UpdateIssuesCommit(pusher, repo, commits.Commits, refName); err != nil { + log.Error("updateIssuesCommit: %v", err) + } + if len(commits.Commits) > setting.UI.FeedMaxCommitNum { commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum] } commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID) notification.NotifyPushCommits(pusher, repo, opts, commits) - if err := repofiles.UpdateIssuesCommit(pusher, repo, commits.Commits, refName); err != nil { - log.Error("updateIssuesCommit: %v", err) - } - if err = models.RemoveDeletedBranch(repo.ID, branch); err != nil { log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, branch, err) } diff --git a/services/webhook/deliver.go b/services/webhook/deliver.go index a417a9e846d49..8243fde1bb743 100644 --- a/services/webhook/deliver.go +++ b/services/webhook/deliver.go @@ -6,8 +6,13 @@ package webhook import ( "context" + "crypto/hmac" + "crypto/sha1" + "crypto/sha256" "crypto/tls" + "encoding/hex" "fmt" + "io" "io/ioutil" "net" "net/http" @@ -26,27 +31,32 @@ import ( // Deliver deliver hook task func Deliver(t *models.HookTask) error { + w, err := models.GetWebhookByID(t.HookID) + if err != nil { + return err + } + defer func() { err := recover() if err == nil { return } // There was a panic whilst delivering a hook... - log.Error("PANIC whilst trying to deliver webhook[%d] for repo[%d] to %s Panic: %v\nStacktrace: %s", t.ID, t.RepoID, t.URL, err, log.Stack(2)) + log.Error("PANIC whilst trying to deliver webhook[%d] for repo[%d] to %s Panic: %v\nStacktrace: %s", t.ID, t.RepoID, w.URL, err, log.Stack(2)) }() + t.IsDelivered = true var req *http.Request - var err error - switch t.HTTPMethod { + switch w.HTTPMethod { case "": log.Info("HTTP Method for webhook %d empty, setting to POST as default", t.ID) fallthrough case http.MethodPost: - switch t.ContentType { + switch w.ContentType { case models.ContentTypeJSON: - req, err = http.NewRequest("POST", t.URL, strings.NewReader(t.PayloadContent)) + req, err = http.NewRequest("POST", w.URL, strings.NewReader(t.PayloadContent)) if err != nil { return err } @@ -57,16 +67,15 @@ func Deliver(t *models.HookTask) error { "payload": []string{t.PayloadContent}, } - req, err = http.NewRequest("POST", t.URL, strings.NewReader(forms.Encode())) + req, err = http.NewRequest("POST", w.URL, strings.NewReader(forms.Encode())) if err != nil { - return err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } case http.MethodGet: - u, err := url.Parse(t.URL) + u, err := url.Parse(w.URL) if err != nil { return err } @@ -78,31 +87,48 @@ func Deliver(t *models.HookTask) error { return err } case http.MethodPut: - switch t.Typ { + switch w.Type { case models.MATRIX: - req, err = getMatrixHookRequest(t) + req, err = getMatrixHookRequest(w, t) if err != nil { return err } default: - return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, t.HTTPMethod) + return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, w.HTTPMethod) } default: - return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, t.HTTPMethod) + return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, w.HTTPMethod) + } + + var signatureSHA1 string + var signatureSHA256 string + if len(w.Secret) > 0 { + sig1 := hmac.New(sha1.New, []byte(w.Secret)) + sig256 := hmac.New(sha256.New, []byte(w.Secret)) + _, err = io.MultiWriter(sig1, sig256).Write([]byte(t.PayloadContent)) + if err != nil { + log.Error("prepareWebhooks.sigWrite: %v", err) + } + signatureSHA1 = hex.EncodeToString(sig1.Sum(nil)) + signatureSHA256 = hex.EncodeToString(sig256.Sum(nil)) } req.Header.Add("X-Gitea-Delivery", t.UUID) req.Header.Add("X-Gitea-Event", t.EventType.Event()) - req.Header.Add("X-Gitea-Signature", t.Signature) + req.Header.Add("X-Gitea-Signature", signatureSHA256) req.Header.Add("X-Gogs-Delivery", t.UUID) req.Header.Add("X-Gogs-Event", t.EventType.Event()) - req.Header.Add("X-Gogs-Signature", t.Signature) + req.Header.Add("X-Gogs-Signature", signatureSHA256) + req.Header.Add("X-Hub-Signature", "sha1="+signatureSHA1) + req.Header.Add("X-Hub-Signature-256", "sha256="+signatureSHA256) req.Header["X-GitHub-Delivery"] = []string{t.UUID} req.Header["X-GitHub-Event"] = []string{t.EventType.Event()} // Record delivery information. t.RequestInfo = &models.HookRequest{ - Headers: map[string]string{}, + URL: req.URL.String(), + HTTPMethod: req.Method, + Headers: map[string]string{}, } for k, vals := range req.Header { t.RequestInfo.Headers[k] = strings.Join(vals, ",") @@ -125,11 +151,6 @@ func Deliver(t *models.HookTask) error { } // Update webhook last delivery status. - w, err := models.GetWebhookByID(t.HookID) - if err != nil { - log.Error("GetWebhookByID: %v", err) - return - } if t.IsSucceed { w.LastStatus = models.HookStatusSucceed } else { diff --git a/services/webhook/dingtalk.go b/services/webhook/dingtalk.go index d781b8c87dbf6..49e161ea57b5e 100644 --- a/services/webhook/dingtalk.go +++ b/services/webhook/dingtalk.go @@ -25,9 +25,6 @@ var ( _ PayloadConvertor = &DingtalkPayload{} ) -// SetSecret sets the dingtalk secret -func (d *DingtalkPayload) SetSecret(_ string) {} - // JSONPayload Marshals the DingtalkPayload to json func (d *DingtalkPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary diff --git a/services/webhook/discord.go b/services/webhook/discord.go index 378d9ff725db6..ea3879f1980d0 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -97,9 +97,6 @@ var ( redColor = color("ff3232") ) -// SetSecret sets the discord secret -func (d *DiscordPayload) SetSecret(_ string) {} - // JSONPayload Marshals the DiscordPayload to json func (d *DiscordPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary diff --git a/services/webhook/feishu.go b/services/webhook/feishu.go index 5c80efb820db7..b280e67759ce5 100644 --- a/services/webhook/feishu.go +++ b/services/webhook/feishu.go @@ -35,9 +35,6 @@ func newFeishuTextPayload(text string) *FeishuPayload { } } -// SetSecret sets the Feishu secret -func (f *FeishuPayload) SetSecret(_ string) {} - // JSONPayload Marshals the FeishuPayload to json func (f *FeishuPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index 1658dd4b44e97..6fca67ca84f97 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -76,9 +76,6 @@ type MatrixPayloadSafe struct { Commits []*api.PayloadCommit `json:"io.gitea.commits,omitempty"` } -// SetSecret sets the Matrix secret -func (m *MatrixPayloadUnsafe) SetSecret(_ string) {} - // JSONPayload Marshals the MatrixPayloadUnsafe to json func (m *MatrixPayloadUnsafe) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary @@ -263,7 +260,7 @@ func getMessageBody(htmlText string) string { // getMatrixHookRequest creates a new request which contains an Authorization header. // The access_token is removed from t.PayloadContent -func getMatrixHookRequest(t *models.HookTask) (*http.Request, error) { +func getMatrixHookRequest(w *models.Webhook, t *models.HookTask) (*http.Request, error) { payloadunsafe := MatrixPayloadUnsafe{} json := jsoniter.ConfigCompatibleWithStandardLibrary if err := json.Unmarshal([]byte(t.PayloadContent), &payloadunsafe); err != nil { @@ -288,9 +285,9 @@ func getMatrixHookRequest(t *models.HookTask) (*http.Request, error) { return nil, fmt.Errorf("getMatrixHookRequest: unable to hash payload: %+v", err) } - t.URL = fmt.Sprintf("%s/%s", t.URL, txnID) + url := fmt.Sprintf("%s/%s", w.URL, txnID) - req, err := http.NewRequest(t.HTTPMethod, t.URL, strings.NewReader(string(payload))) + req, err := http.NewRequest(w.HTTPMethod, url, strings.NewReader(string(payload))) if err != nil { return nil, err } diff --git a/services/webhook/matrix_test.go b/services/webhook/matrix_test.go index 7b10e21cfa4a3..451dff69495f4 100644 --- a/services/webhook/matrix_test.go +++ b/services/webhook/matrix_test.go @@ -184,6 +184,8 @@ func TestMatrixJSONPayload(t *testing.T) { } func TestMatrixHookRequest(t *testing.T) { + w := &models.Webhook{} + h := &models.HookTask{ PayloadContent: `{ "body": "[[user1/test](http://localhost:3000/user1/test)] user1 pushed 1 commit to [master](http://localhost:3000/user1/test/src/branch/master):\n[5175ef2](http://localhost:3000/user1/test/commit/5175ef26201c58b035a3404b3fe02b4e8d436eee): Merge pull request 'Change readme.md' (#2) from add-matrix-webhook into master\n\nReviewed-on: http://localhost:3000/user1/test/pulls/2\n - user1", @@ -245,7 +247,7 @@ func TestMatrixHookRequest(t *testing.T) { ] }` - req, err := getMatrixHookRequest(h) + req, err := getMatrixHookRequest(w, h) require.NoError(t, err) require.NotNil(t, req) diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index 51bb28a36181d..035dbc1c4cf23 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -55,9 +55,6 @@ type ( } ) -// SetSecret sets the MSTeams secret -func (m *MSTeamsPayload) SetSecret(_ string) {} - // JSONPayload Marshals the MSTeamsPayload to json func (m *MSTeamsPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary diff --git a/services/webhook/slack.go b/services/webhook/slack.go index 1de9c9c37c70c..f522ca35f2f0c 100644 --- a/services/webhook/slack.go +++ b/services/webhook/slack.go @@ -56,9 +56,6 @@ type SlackAttachment struct { Text string `json:"text"` } -// SetSecret sets the slack secret -func (s *SlackPayload) SetSecret(_ string) {} - // JSONPayload Marshals the SlackPayload to json func (s *SlackPayload) JSONPayload() ([]byte, error) { json := jsoniter.ConfigCompatibleWithStandardLibrary diff --git a/services/webhook/telegram.go b/services/webhook/telegram.go index f71352141dee2..4c4230759d318 100644 --- a/services/webhook/telegram.go +++ b/services/webhook/telegram.go @@ -45,9 +45,6 @@ var ( _ PayloadConvertor = &TelegramPayload{} ) -// SetSecret sets the telegram secret -func (t *TelegramPayload) SetSecret(_ string) {} - // JSONPayload Marshals the TelegramPayload to json func (t *TelegramPayload) JSONPayload() ([]byte, error) { t.ParseMode = "HTML" diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go index cc79ec15d1d7a..d094a7754bac8 100644 --- a/services/webhook/webhook.go +++ b/services/webhook/webhook.go @@ -5,9 +5,6 @@ package webhook import ( - "crypto/hmac" - "crypto/sha256" - "encoding/hex" "fmt" "strings" @@ -21,12 +18,12 @@ import ( ) type webhook struct { - name models.HookTaskType + name models.HookType payloadCreator func(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error) } var ( - webhooks = map[models.HookTaskType]*webhook{ + webhooks = map[models.HookType]*webhook{ models.SLACK: { name: models.SLACK, payloadCreator: GetSlackPayload, @@ -60,7 +57,7 @@ var ( // RegisterWebhook registers a webhook func RegisterWebhook(name string, webhook *webhook) { - webhooks[models.HookTaskType(name)] = webhook + webhooks[models.HookType(name)] = webhook } // IsValidHookTaskType returns true if a webhook registered @@ -68,7 +65,7 @@ func IsValidHookTaskType(name string) bool { if name == models.GITEA || name == models.GOGS { return true } - _, ok := webhooks[models.HookTaskType(name)] + _, ok := webhooks[models.HookType(name)] return ok } @@ -161,35 +158,14 @@ func prepareWebhook(w *models.Webhook, repo *models.Repository, event models.Hoo return fmt.Errorf("create payload for %s[%s]: %v", w.Type, event, err) } } else { - p.SetSecret(w.Secret) payloader = p } - var signature string - if len(w.Secret) > 0 { - data, err := payloader.JSONPayload() - if err != nil { - log.Error("prepareWebhooks.JSONPayload: %v", err) - } - sig := hmac.New(sha256.New, []byte(w.Secret)) - _, err = sig.Write(data) - if err != nil { - log.Error("prepareWebhooks.sigWrite: %v", err) - } - signature = hex.EncodeToString(sig.Sum(nil)) - } - if err = models.CreateHookTask(&models.HookTask{ - RepoID: repo.ID, - HookID: w.ID, - Typ: w.Type, - URL: w.URL, - Signature: signature, - Payloader: payloader, - HTTPMethod: w.HTTPMethod, - ContentType: w.ContentType, - EventType: event, - IsSSL: w.IsSSL, + RepoID: repo.ID, + HookID: w.ID, + Payloader: payloader, + EventType: event, }); err != nil { return fmt.Errorf("CreateHookTask: %v", err) } diff --git a/templates/admin/user/edit.tmpl b/templates/admin/user/edit.tmpl index af01489c0af26..5e5bc75c9695c 100644 --- a/templates/admin/user/edit.tmpl +++ b/templates/admin/user/edit.tmpl @@ -28,6 +28,33 @@ + +
    + + +
    +
    diff --git a/templates/admin/user/new.tmpl b/templates/admin/user/new.tmpl index 885045dd02708..a433c5a7cc865 100644 --- a/templates/admin/user/new.tmpl +++ b/templates/admin/user/new.tmpl @@ -24,6 +24,31 @@
    + +
    + + +
    +
    diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 10fc2bad4a027..5091eda1e9969 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -30,6 +30,7 @@ AppVer: '{{AppVer}}', AppSubUrl: '{{AppSubUrl}}', AssetUrlPrefix: '{{AssetUrlPrefix}}', + CustomEmojis: {{CustomEmojis}}, UseServiceWorker: {{UseServiceWorker}}, csrf: '{{.CsrfToken}}', HighlightJS: {{if .RequireHighlightJS}}true{{else}}false{{end}}, diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index 638683b25e5b9..c7c497088a9e2 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -23,11 +23,40 @@
    - - - - - + {{range $row := .BlameRows}} + + + + + + + {{end}}
    {{.BlameCommitInfo}}{{.BlameLineNums}}
      {{.BlameContent}}
    +
    +
    +
    + {{$row.Avatar}} +
    + +
    + {{$row.CommitSince}} +
    +
    +
    +
    + {{if $row.PreviousSha}} + + {{svg "octicon-versions"}} + + {{end}} + + + + {{$row.Code}} +
    diff --git a/templates/repo/diff/conversation.tmpl b/templates/repo/diff/conversation.tmpl index ea268c5c170e3..6a6befb5a44a2 100644 --- a/templates/repo/diff/conversation.tmpl +++ b/templates/repo/diff/conversation.tmpl @@ -27,6 +27,14 @@
    +
    + + +
    {{if and $.CanMarkConversation $isNotPending}}
    @@ -42,10 +42,19 @@ git push -u origin {{.Repository.DefaultBranch}}

    {{.i18n.Tr "repo.push_exist_repo"}}

    -
    git remote add origin {{if $.DisableSSH}}{{$.CloneLink.HTTPS}}{{else}}{{$.CloneLink.SSH}}{{end}}
    +									
    git remote add origin {{$.CloneLink.HTTPS}}
     git push -u origin {{.Repository.DefaultBranch}}
    + {{end}} {{else}}
    diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index de31430ce0599..dcc0401c99962 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -462,7 +462,7 @@ {{ range $filename, $lines := .Review.CodeComments}} {{range $line, $comms := $lines}}
    -
    +
    {{$invalid := (index $comms 0).Invalidated}} {{$resolved := (index $comms 0).IsResolved}} {{$resolveDoer := (index $comms 0).ResolveDoer}} diff --git a/templates/repo/migrate/migrating.tmpl b/templates/repo/migrate/migrating.tmpl index c1f189553f6fc..cc12243205c15 100644 --- a/templates/repo/migrate/migrating.tmpl +++ b/templates/repo/migrate/migrating.tmpl @@ -28,6 +28,12 @@

    {{.i18n.Tr "repo.migrate.migrating_failed" .CloneAddr | Safe}}

    + {{if and .Failed .Permission.IsAdmin}} +
    +
    + +
    + {{end}}
    @@ -35,4 +41,37 @@ + {{template "base/footer" .}} diff --git a/templates/repo/settings/webhook/history.tmpl b/templates/repo/settings/webhook/history.tmpl index cf4884531db7a..d2fe68738f5f4 100644 --- a/templates/repo/settings/webhook/history.tmpl +++ b/templates/repo/settings/webhook/history.tmpl @@ -44,8 +44,8 @@
    {{if .RequestInfo}}
    {{$.i18n.Tr "repo.settings.webhook.headers"}}
    -
    Request URL: {{.URL}}
    -Request method: {{if .HTTPMethod}}{{.HTTPMethod}}{{else}}POST{{end}}
    +								
    Request URL: {{.RequestInfo.URL}}
    +Request method: {{if .RequestInfo.HTTPMethod}}{{.RequestInfo.HTTPMethod}}{{else}}POST{{end}}
     {{ range $key, $val := .RequestInfo.Headers }}{{$key}}: {{$val}}
     {{end}}
    {{$.i18n.Tr "repo.settings.webhook.payload"}}
    diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 9453b1af32c1a..669e3552cc5de 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -7333,6 +7333,62 @@ } } }, + "/repos/{owner}/{repo}/pulls/{index}/commits": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Get commits for a pull request", + "operationId": "repoGetPullRequestCommits", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "description": "index of the pull request to get", + "name": "index", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "page number of results to return (1-based)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size of results", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/CommitList" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/pulls/{index}/merge": { "get": { "produces": [ @@ -9721,6 +9777,61 @@ } } }, + "/repos/{template_owner}/{template_repo}/generate": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Create a repository using a template", + "operationId": "generateRepo", + "parameters": [ + { + "type": "string", + "description": "name of the template repository owner", + "name": "template_owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the template repository", + "name": "template_repo", + "in": "path", + "required": true + }, + { + "name": "body", + "in": "body", + "schema": { + "$ref": "#/definitions/GenerateRepoOption" + } + } + ], + "responses": { + "201": { + "$ref": "#/responses/Repository" + }, + "403": { + "$ref": "#/responses/forbidden" + }, + "404": { + "$ref": "#/responses/notFound" + }, + "409": { + "description": "The repository with the same name already exists." + }, + "422": { + "$ref": "#/responses/validationError" + } + } + } + }, "/repositories/{id}": { "get": { "produces": [ @@ -13334,6 +13445,10 @@ "username": { "type": "string", "x-go-name": "Username" + }, + "visibility": { + "type": "string", + "x-go-name": "Visibility" } }, "x-go-package": "code.gitea.io/gitea/modules/structs" @@ -14143,6 +14258,10 @@ "format": "int64", "x-go-name": "SourceID" }, + "visibility": { + "type": "string", + "x-go-name": "Visibility" + }, "website": { "type": "string", "x-go-name": "Website" @@ -14473,6 +14592,13 @@ }, "x-go-name": "AllowedReactions" }, + "custom_emojis": { + "type": "array", + "items": { + "type": "string" + }, + "x-go-name": "CustomEmojis" + }, "default_theme": { "type": "string", "x-go-name": "DefaultTheme" @@ -14480,6 +14606,68 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "GenerateRepoOption": { + "description": "GenerateRepoOption options when creating repository using a template", + "type": "object", + "required": [ + "owner", + "name" + ], + "properties": { + "avatar": { + "description": "include avatar of the template repo", + "type": "boolean", + "x-go-name": "Avatar" + }, + "description": { + "description": "Description of the repository to create", + "type": "string", + "x-go-name": "Description" + }, + "git_content": { + "description": "include git content of default branch in template repo", + "type": "boolean", + "x-go-name": "GitContent" + }, + "git_hooks": { + "description": "include git hooks in template repo", + "type": "boolean", + "x-go-name": "GitHooks" + }, + "labels": { + "description": "include labels in template repo", + "type": "boolean", + "x-go-name": "Labels" + }, + "name": { + "description": "Name of the repository to create", + "type": "string", + "uniqueItems": true, + "x-go-name": "Name" + }, + "owner": { + "description": "The organization or person who will own the new repository", + "type": "string", + "x-go-name": "Owner" + }, + "private": { + "description": "Whether the repository is private", + "type": "boolean", + "x-go-name": "Private" + }, + "topics": { + "description": "include topics in template repo", + "type": "boolean", + "x-go-name": "Topics" + }, + "webhooks": { + "description": "include webhooks in template repo", + "type": "boolean", + "x-go-name": "Webhooks" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "GitBlobResponse": { "description": "GitBlobResponse represents a git blob", "type": "object", @@ -15226,8 +15414,7 @@ "x-go-name": "Title" }, "type": { - "type": "string", - "x-go-name": "Type" + "$ref": "#/definitions/NotifySubjectType" }, "url": { "type": "string", @@ -15271,6 +15458,11 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "NotifySubjectType": { + "description": "NotifySubjectType represent type of notification subject", + "type": "string", + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "OAuth2Application": { "type": "object", "title": "OAuth2Application represents an OAuth2 application.", @@ -16637,6 +16829,11 @@ "format": "int64", "x-go-name": "StarredRepos" }, + "visibility": { + "description": "User visibility level option: public, limited, private", + "type": "string", + "x-go-name": "Visibility" + }, "website": { "description": "the user's website", "type": "string", diff --git a/templates/user/auth/forgot_passwd.tmpl b/templates/user/auth/forgot_passwd.tmpl index 241deeed4a798..2ff7acb97de43 100644 --- a/templates/user/auth/forgot_passwd.tmpl +++ b/templates/user/auth/forgot_passwd.tmpl @@ -22,7 +22,13 @@
    {{else if .IsResetDisable}} -

    {{.i18n.Tr "auth.disable_forgot_password_mail"}}

    +

    + {{if $.IsAdmin}} + {{.i18n.Tr "auth.disable_forgot_password_mail_admin"}} + {{else}} + {{.i18n.Tr "auth.disable_forgot_password_mail"}} + {{end}} +

    {{else if .ResendLimited}}

    {{.i18n.Tr "auth.resent_limit_prompt"}}

    {{end}} diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl index 057a4a76256e0..6ed75ee1490c9 100644 --- a/templates/user/dashboard/feeds.tmpl +++ b/templates/user/dashboard/feeds.tmpl @@ -101,7 +101,7 @@ {{end}} {{end}} - {{if and (gt $push.Len 1) $push.CompareURL}}
  • {{$.i18n.Tr "action.compare_commits" $push.Len}} »
  • {{end}} + {{if and (gt (len $push.Commits) 1) $push.CompareURL}}
  • {{$.i18n.Tr "action.compare_commits" (len $push.Commits)}} »
  • {{end}} {{else if eq .GetOpType 6}} diff --git a/templates/user/settings/profile.tmpl b/templates/user/settings/profile.tmpl index 9f07226632fcd..1f1585a78773b 100644 --- a/templates/user/settings/profile.tmpl +++ b/templates/user/settings/profile.tmpl @@ -47,27 +47,62 @@ -
    - - ": -4.321923, - "": -8.364974, - "": -8.364974, - "": -6.755536, - "": -8.364974, - "": -6.755536, - "": -4.930987, - "": -6.573215, - "

    ": -4.997678, - "": -7.671827, - "": -5.800025, - "": -6.978680, - "": -5.474602, - "": -7.671827, - "": -8.364974, - "": -5.880067, - "": -8.364974, - "": -5.032769, - "": -6.573215, - "": -6.978680, - "": -5.725917, - "": -6.285532, - "": -8.364974, - "

    ": -8.364974, - "": -4.116479, - "": -6.573215, - "
    ": -7.266362, - "
    ": -6.573215, - "