Compare commits

...

8 Commits

Author SHA1 Message Date
techknowlogick 2dae5b715c
Fix keys test (#17776) 2021-11-23 08:12:02 +00:00
zeripath 188fd2dd1a
Add `PULL_LIMIT` and `PUSH_LIMIT` to cron.update_mirror task (#17568) 2021-11-22 22:09:35 -05:00
silverwind 9450410ff7
Improve ellipsis buttons (#17773)
* Improve ellipsis buttons

- Remove icon font usage
- Add aria-expanded attribute

* rename function to match

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-11-22 21:44:38 -05:00
mscherer e595986458
Harden authorized keys a bit more (#17772)
sshd(8) list restrict as a future-proof way to restrict feature
enabled in ssh. It is supported since OpenSSH 7.2, out since
2016-02-29.

OpenSSH will ignore unknown options (see sshauthopt_parse in
auth-options.c), so it should be safe to add the option and
no-user-rc.

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-11-22 21:44:26 -05:00
velengel a1f5c7bfce
Add copy Commit ID button in commits list (#17759)
* fix: implement commit id copy to clipboard

* fix: remove abundant attributes / consider edge-case

* fix: locale_en fixed

* fix: use ui button

* tune copy button

* fix: button size

* Fix merge

Co-authored-by: Ysmr-Ry <ryo.yossy@live.jp>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-11-22 21:44:10 -05:00
Lunny Xiao b2daa7e203
Add documentation for backend development (#17512)
* Add documentation for backend development

* Update backend guidline

* More sections

* Add modules/setting and modules/git

* Uniform gitea as Gitea

* some improvements

* some improvements
2021-11-23 10:10:18 +08:00
GiteaBot c79cc2d3e8 [skip ci] Updated translations via Crowdin 2021-11-23 00:31:08 +00:00
zeripath 1dbc58f742
More pleasantly handle broken or missing git repositories (#17747)
* More pleasantly handle broken or missing git repositories

In #17742 it was noted that there a completely invalid git repository underlying a
repo on gitea.com. This happened due to a problem during a migration however, it
is not beyond the realms of possibility that a corruption could occur to another
user.

This PR adds a check to RepoAssignment that will detect if a repository loading has
failed due to an absent git repository. It will then show a page suggesting the user
contacts the administrator or deletes the repository.

Fix #17742

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Update options/locale/locale_en-US.ini

Co-authored-by: techknowlogick <techknowlogick@gitea.io>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-11-22 22:32:16 +00:00
37 changed files with 293 additions and 60 deletions

View File

@ -1719,6 +1719,12 @@ PATH =
;RUN_AT_START = false
;; Notice if not success
;NO_SUCCESS_NOTICE = true
;; Limit the number of mirrors added to the queue to this number
;; (negative values mean no limit, 0 will result in no result in no mirrors being queued effectively disabling pull mirror updating.)
;PULL_LIMIT=50
;; Limit the number of mirrors added to the queue to this number
;; (negative values mean no limit, 0 will result in no mirrors being queued effectively disabling push mirror updating)
;PUSH_LIMIT=50
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -828,6 +828,8 @@ NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take ef
- `SCHEDULE`: **@every 10m**: Cron syntax for scheduling update mirrors, e.g. `@every 3h`.
- `NO_SUCCESS_NOTICE`: **true**: The cron task for update mirrors success report is not very useful - as it just means that the mirrors have been queued. Therefore this is turned off by default.
- `PULL_LIMIT`: **50**: Limit the number of mirrors added to the queue to this number (negative values mean no limit, 0 will result in no mirrors being queued effectively disabling pull mirror updating).
- `PUSH_LIMIT`: **50**: Limit the number of mirrors added to the queue to this number (negative values mean no limit, 0 will result in no mirrors being queued effectively disabling push mirror updating).
#### Cron - Repository Health Check (`cron.repo_health_check`)

View File

@ -0,0 +1,13 @@
---
date: "2016-12-01T16:00:00+02:00"
title: "开发者"
slug: "developers"
weight: 40
toc: false
draft: false
menu:
sidebar:
name: "开发者"
weight: 50
identifier: "developers"
---

View File

@ -0,0 +1,115 @@
---
date: "2021-11-01T23:41:00+08:00"
title: "Guidelines for Backend Development"
slug: "guidelines-backend"
weight: 20
toc: false
draft: false
menu:
sidebar:
parent: "developers"
name: "Guidelines for Backend"
weight: 20
identifier: "guidelines-backend"
---
# Guidelines for Backend Development
**Table of Contents**
{{< toc >}}
## Background
Gitea uses Golang as the backend programming language. It uses many third-party packages and also write some itself.
For example, Gitea uses [Chi](https://github.com/go-chi/chi) as basic web framework. [Xorm](https://xorm.io) is an ORM framework that is used to interact with the database.
So it's very important to manage these packages. Please take the below guidelines before you start to write backend code.
## Package Design Guideline
### Packages List
To maintain understandable code and avoid circular dependencies it is important to have a good code structure. The Gitea backend is divided into the following parts:
- `build`: Scripts to help build Gitea.
- `cmd`: All Gitea actual sub commands includes web, doctor, serv, hooks, admin and etc. `web` will start the web service. `serv` and `hooks` will be invoked by git or openSSH. Other sub commands could help to mantain Gitea.
- `integrations`: Integration tests
- `models`: Contains the data structures used by xorm to construct database tables. It also contains functions to query and update the database. Dependencies to other Gitea code should be avoided. You can make exceptions in cases such as logging.
- `models/db`: Basic database operations. All other `models/xxx` packages should depend on this package. The `GetEngine` function should only be invoked from `models/`.
- `models/fixtures`: Sample data used in unit tests and integration tests. One `yml` file means one table which will be loaded into database when beginning the tests.
- `models/migrations`: Stores database migrations between versions. PRs that change a database structure **MUST** also have a migration step.
- `modules`: Different modules to handle specific functionality in Gitea. Work in Progress: Some of them should be moved to `services`.
- `modules/setting`: Store all system configurations read from ini files and has been referenced by everywhere. But they should be used as function parameters when possible.
- `modules/git`: Package to interactive with `Git` command line or Gogit package.
- `public`: Compiled frontend files (javascript, images, css, etc.)
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers.
- `routers/api` Conatins routers for `/api/v1` aims to handle RESTful API requests.
- `routers/install` Could only reponse when system is INSTALL mode.
- `routers/private` will only be invoked by internal sub commands, especially `serv` and `hooks`.
- `routers/web` will handle HTTP requests from web browsers or Git SMART HTTP protocols.
- `services`: Support functions for common routing operations or command executions. Uses `models` and `modules` to handle the requests.
- `templates`: Golang templates for generating the html output.
### Package Dependencies
Since Golang don't support import cycles, we have to decide the package dependencies carefully. There are some levels between those packages. Below is the ideal package dependencies direction.
`cmd` -> `routers` -> `services` -> `models` -> `modules`
From left to right, left packages could depend on right packages, but right packages MUST not depend on left packages. The sub packages on the same level could depend on according this level's rules.
**NOTICE**
Why do we need database transactions outside of `models`? And how?
Some actions should allow for rollback when database record insertion/update/deletion failed.
So services must be allowed to create a database transaction. Here is some example,
```go
// servcies/repository/repo.go
func CreateXXXX() error {\
ctx, committer, err := db.TxContext()
if err != nil {
return err
}
defer committer.Close()
// do something, if return err, it will rollback automatically when `committer.Close()` is invoked.
if err := issues.UpdateIssue(ctx, repoID); err != nil {
// ...
}
// ......
return committer.Commit()
}
```
You should **not** use `db.GetEngine(ctx)` in `services` directly, but just write a function under `models/`.
If the function will be used in the transaction, just let `context.Context` as the function's first parameter.
```go
// models/issues/issue.go
func UpdateIssue(ctx context.Context, repoID int64) error {
e := db.GetEngine(ctx)
// ......
}
```
### Package Name
For the top level package, use a plural as package name, i.e. `services`, `models`, for sub packages, use singular,
i.e. `servcies/user`, `models/repository`.
### Import Alias
Since there are many package levels and sub packages, so you will find `modules/user`, `models/user`, `services/user`. When these packages are import into one Go file, it's difficult to know which package we are using and if it's a variable name or an import name. So we recommand to always use import alias. To differ from package variables which are commonly use camelCase, just use **snake_case** as import package alias.
i.e. `import user_service "code.Gitea.io/Gitea/services/user"`
### Future Tasks
Currently, we are creating some refactors to do the following things:
- Correct that codes which doesn't follow the rules.
- There are too many files in `models`, so we are moving some of them into a sub package `models/xxx`.
- Some `modules` sub packages should be moved to `services` because they depends on `models`.

View File

@ -32,7 +32,7 @@ func Test_CmdKeys(t *testing.T) {
{"with_key",
[]string{"keys", "-e", "git", "-u", "git", "-t", "ssh-rsa", "-k", "AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM="},
false,
"# gitea public key\ncommand=\"" + setting.AppPath + " --config=" + util.ShellEscape(setting.CustomConf) + " serv key-1\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM= user2@localhost\n",
"# gitea public key\ncommand=\"" + setting.AppPath + " --config=" + util.ShellEscape(setting.CustomConf) + " serv key-1\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWVj0fQ5N8wNc0LVNA41wDLYJ89ZIbejrPfg/avyj3u/ZohAKsQclxG4Ju0VirduBFF9EOiuxoiFBRr3xRpqzpsZtnMPkWVWb+akZwBFAx8p+jKdy4QXR/SZqbVobrGwip2UjSrri1CtBxpJikojRIZfCnDaMOyd9Jp6KkujvniFzUWdLmCPxUE9zhTaPu0JsEP7MW0m6yx7ZUhHyfss+NtqmFTaDO+QlMR7L2QkDliN2Jl3Xa3PhuWnKJfWhdAq1Cw4oraKUOmIgXLkuiuxVQ6mD3AiFupkmfqdHq6h+uHHmyQqv3gU+/sD8GbGAhf6ftqhTsXjnv1Aj4R8NoDf9BS6KRkzkeun5UisSzgtfQzjOMEiJtmrep2ZQrMGahrXa+q4VKr0aKJfm+KlLfwm/JztfsBcqQWNcTURiCFqz+fgZw0Ey/de0eyMzldYTdXXNRYCKjs9bvBK+6SSXRM7AhftfQ0ZuoW5+gtinPrnmoOaSCEJbAiEiTO/BzOHgowiM= user2@localhost\n",
},
{"invalid", []string{"keys", "--not-a-flag=git"}, true, "Incorrect Usage: flag provided but not defined: -not-a-flag\n\n"},
}

View File

@ -146,6 +146,7 @@ const (
RepositoryReady RepositoryStatus = iota // a normal repository
RepositoryBeingMigrated // repository is migrating
RepositoryPendingTransfer // repository pending in ownership transfer state
RepositoryBroken // repository is in a permanently broken state
)
// TrustModelType defines the types of trust model for this repository
@ -289,6 +290,11 @@ func (repo *Repository) IsBeingCreated() bool {
return repo.IsBeingMigrated()
}
// IsBroken indicates that repository is broken
func (repo *Repository) IsBroken() bool {
return repo.Status == RepositoryBroken
}
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
func (repo *Repository) AfterLoad() {
// FIXME: use models migration to solve all at once.

View File

@ -119,6 +119,7 @@ func MirrorsIterate(f func(idx int, bean interface{}) error) error {
return db.GetEngine(db.DefaultContext).
Where("next_update_unix<=?", time.Now().Unix()).
And("next_update_unix!=0").
OrderBy("updated_unix ASC").
Iterate(new(Mirror), f)
}

View File

@ -107,5 +107,6 @@ func PushMirrorsIterate(f func(idx int, bean interface{}) error) error {
return db.GetEngine(db.DefaultContext).
Where("last_update + (`interval` / ?) <= ?", time.Second, time.Now().Unix()).
And("`interval` != 0").
OrderBy("last_update ASC").
Iterate(new(PushMirror), f)
}

View File

@ -39,7 +39,7 @@ import (
const (
tplCommentPrefix = `# gitea public key`
tplPublicKey = tplCommentPrefix + "\n" + `command=%s,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n"
tplPublicKey = tplCommentPrefix + "\n" + `command=%s,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict %s` + "\n"
)
var sshOpLocker sync.Mutex

View File

@ -522,14 +522,30 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
}
}
isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink || ctx.Link == ctx.Repo.RepoLink+"/settings" || strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/")
// Disable everything when the repo is being created
if ctx.Repo.Repository.IsBeingCreated() {
if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
if !isHomeOrSettings {
ctx.Redirect(ctx.Repo.RepoLink)
}
return
}
gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
if err != nil {
if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
ctx.Repo.Repository.Status = models.RepositoryBroken
ctx.Repo.Repository.IsEmpty = true
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
// Only allow access to base of repo or settings
if !isHomeOrSettings {
ctx.Redirect(ctx.Repo.RepoLink)
}
return
}
ctx.ServerError("RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
return
}
@ -551,6 +567,17 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
tags, err := ctx.Repo.GitRepo.GetTags(0, 0)
if err != nil {
if strings.Contains(err.Error(), "fatal: not a git repository ") {
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
ctx.Repo.Repository.Status = models.RepositoryBroken
ctx.Repo.Repository.IsEmpty = true
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
// Only allow access to base of repo or settings
if !isHomeOrSettings {
ctx.Redirect(ctx.Repo.RepoLink)
}
return
}
ctx.ServerError("GetTags", err)
return
}
@ -919,6 +946,11 @@ func UnitTypes() func(ctx *Context) {
// IssueTemplatesFromDefaultBranch checks for issue templates in the repo's default branch
func (ctx *Context) IssueTemplatesFromDefaultBranch() []api.IssueTemplate {
var issueTemplates []api.IssueTemplate
if ctx.Repo.Repository.IsEmpty {
return issueTemplates
}
if ctx.Repo.Commit == nil {
var err error
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)

View File

@ -858,8 +858,6 @@ migrate.clone_address=Migrovat / klonovat z URL
migrate.clone_address_desc=HTTP(S) nebo URL pro klonování existujícího repozitáře
migrate.clone_local_path=nebo místní cesta serveru
migrate.permission_denied=Není dovoleno importovat místní repozitáře.
migrate.permission_denied_blocked=Nemáte oprávnění provést import z blokovaných serverů.
migrate.permission_denied_private_ip=Nemáte oprávnění provést import ze soukromých IP adres.
migrate.invalid_local_path=Místní cesta je neplatná, buď neexistuje nebo není adresářem.
migrate.invalid_lfs_endpoint=Koncový bod LFS není platný.
migrate.failed=Přenesení selhalo: %v

View File

@ -884,8 +884,6 @@ migrate.clone_address=Migrations- / Klon-URL
migrate.clone_address_desc=Die HTTP(S)- oder „git clone“-URL eines bereits existierenden Repositorys
migrate.clone_local_path=oder ein lokaler Serverpfad
migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Repositories.
migrate.permission_denied_blocked=Du darfst nicht von geblockten Hosts importieren.
migrate.permission_denied_private_ip=Du darfst nicht von privaten IP-Addressen importieren.
migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner.
migrate.invalid_lfs_endpoint=Ungültiger LFS Endpunkt.
migrate.failed=Fehler bei der Migration: %v

View File

@ -899,8 +899,6 @@ migrate.clone_address_desc=Το HTTP(S) ή Git URL 'κλωνοποίησης' ε
migrate.github_token_desc=Μπορείτε να βάλετε ένα ή περισσότερα διακριτικά χωρίζοντας τα με κόμμα, ώστε να κάνετε τη μεταφορά γρηγορότερη, επειδή το API του Github έχει όριο ρυθμού. ΠΡΟΣΟΧΗ: Η κατάχρηση αυτής της δυνατότητας μπορεί να παραβιάσει την πολιτική του παρόχου υπηρεσιών και να οδηγήσει σε αποκλεισμό λογαριασμού.
migrate.clone_local_path=ή μια διαδρομή τοπικού διακομιστή
migrate.permission_denied=Δεν επιτρέπεται η εισαγωγή τοπικών αποθετηρίων.
migrate.permission_denied_blocked=Δεν επιτρέπεται η εισαγωγή από αποκλεισμένους υπολογιστές.
migrate.permission_denied_private_ip=Δεν επιτρέπεται η εισαγωγή από ιδιωτικές IPs.
migrate.invalid_local_path=Η τοπική διαδρομή δεν είναι έγκυρη. Δεν υπάρχει ή δεν είναι φάκελος.
migrate.invalid_lfs_endpoint=Η διεύθυνση LFS δεν είναι έγκυρο.
migrate.failed=Η μεταφορά απέτυχε: %v

View File

@ -946,6 +946,7 @@ clone_this_repo = Clone this repository
create_new_repo_command = Creating a new repository on the command line
push_exist_repo = Pushing an existing repository from the command line
empty_message = This repository does not contain any content.
broken_message = The git data underlying this repository cannot be read. Contact the administrator of this instance or delete this repository.
code = Code
code.desc = Access source code, files, commits and branches.

View File

@ -895,8 +895,6 @@ migrate.clone_address_desc=La URL HTTP(S) o de Git 'clone' de un repositorio exi
migrate.github_token_desc=Puedes poner uno o más tokens con comas separadas aquí para hacer migrar más rápido debido al límite de velocidad de Github API. PRECAUCIÓN: Abusar esta característica puede violar la política del proveedor de servicios y llevar a bloquear la cuenta.
migrate.clone_local_path=o una ruta local del servidor
migrate.permission_denied=No te está permitido importar repositorios locales.
migrate.permission_denied_blocked=No está permitido importar desde hosts bloqueados.
migrate.permission_denied_private_ip=No está permitido importar desde direcciones IP privadas.
migrate.invalid_local_path=La ruta local es inválida. No existe o no es un directorio.
migrate.invalid_lfs_endpoint=El punto final de LFS no es válido.
migrate.failed=Migración fallida: %v

View File

@ -833,8 +833,6 @@ migrate.clone_address=Migrer/Cloner depuis une URL
migrate.clone_address_desc=L'URL HTTP(S) ou Git "clone" d'un dépôt existant
migrate.clone_local_path=ou un chemin serveur local
migrate.permission_denied=Vous n'êtes pas autorisé à importer des dépôts locaux.
migrate.permission_denied_blocked=Vous n'êtes pas autorisé à importer à partir d'hôtes bloqués.
migrate.permission_denied_private_ip=Vous n'êtes pas autorisé à importer depuis des adresses IP privées.
migrate.invalid_local_path=Chemin local non valide, non existant ou n'étant pas un dossier.
migrate.invalid_lfs_endpoint=Le point d'accès LFS n'est pas valide.
migrate.failed=Echec de migration: %v

View File

@ -899,8 +899,6 @@ migrate.clone_address_desc=既存リポジトリの、HTTP(S)またはGit形式
migrate.github_token_desc=Github APIはレート制限がありますが、移行をより速くするため、ここにカンマ区切りで複数のトークンを入力することができます。 警告: この機能を悪用すると、サービスプロバイダのポリシーに違反し、アカウントがブロックされる可能性があります。
migrate.clone_local_path=、またはローカルサーバー上のパス
migrate.permission_denied=ローカルリポジトリをインポートする権限がありません。
migrate.permission_denied_blocked=ブロックしているホストからのインポートは禁止されています。
migrate.permission_denied_private_ip=プライベートIPからのインポートは禁止されています。
migrate.invalid_local_path=ローカルパスが無効です。 存在しないかディレクトリではありません。
migrate.invalid_lfs_endpoint=LFS エンドポイントが無効です。
migrate.failed=移行に失敗しました: %v

View File

@ -880,8 +880,6 @@ migrate.clone_address=Klonēšanas adrese
migrate.clone_address_desc=Tā var būt HTTP(S) adrese vai Git 'clone' URL eksistējošam repozitorijam
migrate.clone_local_path=vai servera lokālais ceļš
migrate.permission_denied=Jums nav tiesību importēt lokālu repozitoriju.
migrate.permission_denied_blocked=Nav atļauts veikt importu no bloķētiem serveriem.
migrate.permission_denied_private_ip=Nav atļauts veikt importu no bloķētiem no privātām IP adresēm.
migrate.invalid_local_path=Nederīgs lokālais ceļš. Tas neeksistē vai nav direktorija.
migrate.invalid_lfs_endpoint=LFS galapunkts nav korekts.
migrate.failed=Migrācija neizdevās: %v

View File

@ -840,8 +840,6 @@ migrate.clone_address_desc=URL HTTP (S) ou Git 'clone' de um repositório existe
migrate.github_token_desc=Você pode colocar aqui um ou mais tokens separados com vírgula para tornar a migração mais rápida devido ao limite de taxa de API do Github. AVISO: abusar desse recurso pode violar a política do provedor de serviço e levar ao bloqueio da conta.
migrate.clone_local_path=ou um caminho de servidor local
migrate.permission_denied=Você não pode importar repositórios locais.
migrate.permission_denied_blocked=Você não tem permissão para importar de origens bloqueadas.
migrate.permission_denied_private_ip=Você não tem permissão para importar de IPs privados.
migrate.invalid_local_path=O caminho local é inválido. Ele não existe ou não é um diretório.
migrate.invalid_lfs_endpoint=O destino LFS não é válido.
migrate.failed=Migração falhou: %v

View File

@ -898,8 +898,6 @@ migrate.clone_address_desc=O URL de clonagem HTTP(S) ou Git de um repositório e
migrate.github_token_desc=Pode colocar aqui um ou mais códigos separados por vírgulas para tornar mais rápida a migração, para compensar a limitação de velocidade da API do GitHub. AVISO: O abuso desta funcionalidade poderá violar a política do seu fornecedor de serviço e levar ao bloqueio da conta.
migrate.clone_local_path=ou um caminho no servidor local
migrate.permission_denied=Não está autorizado a importar repositórios locais.
migrate.permission_denied_blocked=Não tem permissão para importar a partir de servidores bloqueados.
migrate.permission_denied_private_ip=Não tem permissão para importar a partir de IPs privados.
migrate.invalid_local_path=O caminho local é inválido. Não existe ou não é uma pasta.
migrate.invalid_lfs_endpoint=O destino LFS não é válido.
migrate.failed=A migração falhou: %v

View File

@ -886,8 +886,6 @@ migrate.clone_address=Перенос / Клонирование по URL
migrate.clone_address_desc=Это может быть HTTP/HTTPS/GIT адрес или локальный путь существующего репозитория на сервере.
migrate.clone_local_path=или путь к локальному серверу
migrate.permission_denied=У вас нет прав на импорт локальных репозиториев.
migrate.permission_denied_blocked=Вам не разрешено импортировать с заблокированных узлов.
migrate.permission_denied_private_ip=Вы не можете импортировать с приватных IP.
migrate.invalid_local_path=Недопустимый локальный путь. Возможно он не существует или не является папкой.
migrate.invalid_lfs_endpoint=Конечная точка LFS недействительна.
migrate.failed=Миграция не удалась: %v

View File

@ -868,8 +868,6 @@ migrate.clone_address=URL'den Taşı / Klonla
migrate.clone_address_desc=Varolan bir deponun HTTP(S) veya Git 'klonlama' URL'si
migrate.clone_local_path=veya bir yerel sunucu yolu
migrate.permission_denied=Yerel depoları içeri aktarma izniniz yok.
migrate.permission_denied_blocked=Engellenen ana bilgisayarlardan içeri aktarmanıza izin verilmiyor.
migrate.permission_denied_private_ip=Özel IP'lerden içeri aktarmanıza izin verilmiyor.
migrate.invalid_local_path=Yerel yol geçersiz. Mevcut değil veya bir dizin değil.
migrate.invalid_lfs_endpoint=LFS Uç noktası geçerli değil.
migrate.failed=Göç başarısız: %v

View File

@ -860,8 +860,6 @@ migrate.clone_address=Міграція / клонувати з URL-адреси
migrate.clone_address_desc=URL-адреса HTTP(S) або Git "clone" існуючого репозиторія
migrate.clone_local_path=або шлях до локального серверу
migrate.permission_denied=Вам не дозволено імпортувати локальні репозиторії.
migrate.permission_denied_blocked=Вам не дозволено імпортувати з заблокованих хостів.
migrate.permission_denied_private_ip=Вам не дозволено імпортувати з приватних IP-адрес.
migrate.invalid_local_path=Локальний шлях недійсний. Він не існує або не є каталогом.
migrate.invalid_lfs_endpoint=Помилкова кінцева точка LFS.
migrate.failed=Міграція не вдалася: %v

View File

@ -899,8 +899,6 @@ migrate.clone_address_desc=现有仓库的 HTTP(s) 或 Git "clone" URL
migrate.github_token_desc=由于 Github API 速率限制,您可以在此处放置一个或多个以逗号分隔的令牌,以加快迁移速度。警告:滥用此功能可能会违反服务提供商的政策并导致帐户被封。
migrate.clone_local_path=或服务器本地路径
migrate.permission_denied=您没有获得导入本地仓库的权限。
migrate.permission_denied_blocked=不允许从被屏蔽的主机导入。
migrate.permission_denied_private_ip=不允许从私有IP导入。
migrate.invalid_local_path=无效的本地路径,不存在或不是一个目录!
migrate.invalid_lfs_endpoint=LFS 网址无效。
migrate.failed=迁移失败:%v

View File

@ -899,8 +899,7 @@ migrate.clone_address_desc=現有存儲庫的 HTTP(S) 或 Git Clone URL
migrate.github_token_desc=由於 Github API 的速率限制,您可在此輸入一個或多個由半形逗號「,」分隔的 Token 來加快遷移速度。警告:濫用此功能可能會違反該服務提供者的政策並導致帳戶被封鎖。
migrate.clone_local_path=或者是本地端伺服器路徑
migrate.permission_denied=您並沒有導入本地儲存庫的權限。
migrate.permission_denied_blocked=您未被允許從已封鎖的主機匯入。
migrate.permission_denied_private_ip=您未被允許從私有 IP 匯入。
migrate.permission_denied_blocked=您無法從未允許的主機匯入,請聯絡管理員檢查以下設定值 ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS
migrate.invalid_local_path=無效的本地路徑,該路徑不存在或不是一個目錄!
migrate.invalid_lfs_endpoint=該 LFS 端點無效。
migrate.failed=遷移失敗:%v
@ -2043,6 +2042,7 @@ diff.file_suppressed=檔案差異因為檔案過大而無法顯示
diff.file_suppressed_line_too_long=檔案差異因為一行或多行太長而無法顯示
diff.too_many_files=本差異變更的檔案數量過多導致部分檔案未顯示
diff.show_more=顯示更多
diff.load=載入差異
diff.generated=generated
diff.vendored=vendored
diff.comment.placeholder=留言...

View File

@ -162,6 +162,14 @@ func ServCommand(ctx *context.PrivateContext) {
return
}
if repo.IsBroken() {
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: "Repository is in a broken state",
})
return
}
// We can shortcut at this point if the repo is a mirror
if mode > models.AccessModeRead && repo.IsMirror {
ctx.JSON(http.StatusForbidden, private.ErrServCommand{

View File

@ -18,13 +18,24 @@ import (
)
func registerUpdateMirrorTask() {
RegisterTaskFatal("update_mirrors", &BaseConfig{
Enabled: true,
RunAtStart: false,
Schedule: "@every 10m",
NoSuccessNotice: true,
}, func(ctx context.Context, _ *models.User, _ Config) error {
return mirror_service.Update(ctx)
type UpdateMirrorTaskConfig struct {
BaseConfig
PullLimit int
PushLimit int
}
RegisterTaskFatal("update_mirrors", &UpdateMirrorTaskConfig{
BaseConfig: BaseConfig{
Enabled: true,
RunAtStart: false,
Schedule: "@every 10m",
NoSuccessNotice: true,
},
PullLimit: 50,
PushLimit: 50,
}, func(ctx context.Context, _ *models.User, cfg Config) error {
umtc := cfg.(*UpdateMirrorTaskConfig)
return mirror_service.Update(ctx, umtc.PullLimit, umtc.PushLimit)
})
}

View File

@ -45,15 +45,19 @@ func doMirrorSync(ctx context.Context, req *SyncRequest) {
}
}
var errLimit = fmt.Errorf("reached limit")
// Update checks and updates mirror repositories.
func Update(ctx context.Context) error {
func Update(ctx context.Context, pullLimit, pushLimit int) error {
if !setting.Mirror.Enabled {
log.Warn("Mirror feature disabled, but cron job enabled: skip update")
return nil
}
log.Trace("Doing: Update")
handler := func(idx int, bean interface{}) error {
requested := 0
handler := func(idx int, bean interface{}, limit int) error {
var item SyncRequest
if m, ok := bean.(*models.Mirror); ok {
if m.Repo == nil {
@ -78,21 +82,49 @@ func Update(ctx context.Context) error {
return nil
}
// Check we've not been cancelled
select {
case <-ctx.Done():
return fmt.Errorf("Aborted")
return fmt.Errorf("aborted")
default:
return mirrorQueue.Push(&item)
}
// Check if this request is already in the queue
has, err := mirrorQueue.Has(&item)
if err != nil {
return err
}
if has {
return nil
}
// Push to the Queue
if err := mirrorQueue.Push(&item); err != nil {
return err
}
requested++
if limit > 0 && requested > limit {
return errLimit
}
return nil
}
if err := models.MirrorsIterate(handler); err != nil {
log.Error("MirrorsIterate: %v", err)
return err
if pullLimit != 0 {
if err := models.MirrorsIterate(func(idx int, bean interface{}) error {
return handler(idx, bean, pullLimit)
}); err != nil && err != errLimit {
log.Error("MirrorsIterate: %v", err)
return err
}
}
if err := models.PushMirrorsIterate(handler); err != nil {
log.Error("PushMirrorsIterate: %v", err)
return err
if pushLimit != 0 {
if err := models.PushMirrorsIterate(func(idx int, bean interface{}) error {
return handler(idx, bean, pushLimit)
}); err != nil && err != errLimit {
log.Error("PushMirrorsIterate: %v", err)
return err
}
}
log.Trace("Finished: Update")
return nil

View File

@ -23,7 +23,8 @@
{{$userName}}
{{end}}
</td>
<td class="sha">
<td class="sha df">
<button class="ui button copy-commit-sha df ac" data-clipboard-text="{{.ID}}">{{svg "octicon-copy" 14}}</button>
{{$class := "ui sha label"}}
{{if .Signature}}
{{$class = (printf "%s%s" $class " isSigned")}}
@ -66,7 +67,7 @@
{{end}}
</span>
{{if IsMultilineCommitMessage .Message}}
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
<button class="ui button ellipsis-button" aria-expanded="false">...</button>
{{end}}
{{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses "root" $}}
{{if IsMultilineCommitMessage .Message}}

View File

@ -49,7 +49,7 @@
{{ $commitLink:= printf "%s/commit/%s" $.comment.Issue.PullRequest.BaseRepo.Link (PathEscape .ID.String) }}
<span class="mono commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject .Message ($.comment.Issue.PullRequest.BaseRepo.Link|Escape) $commitLink $.comment.Issue.PullRequest.BaseRepo.ComposeMetas}}</span>
{{if IsMultilineCommitMessage .Message}}
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
<button class="ui button ellipsis-button" aria-expanded="false">...</button>
{{end}}
{{if IsMultilineCommitMessage .Message}}
<pre class="commit-body" style="display: none;">{{RenderCommitBody .Message ($.comment.Issue.PullRequest.BaseRepo.Link|Escape) $.comment.Issue.PullRequest.BaseRepo.ComposeMetas}}</pre>

View File

@ -10,7 +10,11 @@
{{.i18n.Tr "repo.archive.title"}}
</div>
{{end}}
{{if .CanWriteCode}}
{{if .Repository.IsBroken}}
<div class="ui segment center">
{{.i18n.Tr "repo.broken_message"}}
</div>
{{else if .CanWriteCode}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.quick_guide"}}
</h4>

View File

@ -40,7 +40,7 @@
{{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{.BaseRepo.FullName}}</a></div>{{end}}
{{if .IsGenerated}}<div class="fork-flag">{{$.i18n.Tr "repo.generated_from"}} <a href="{{.TemplateRepo.Link}}">{{.TemplateRepo.FullName}}</a></div>{{end}}
</div>
{{if not .IsBeingCreated}}
{{if not (or .IsBeingCreated .IsBroken)}}
<div class="repo-buttons">
{{if $.RepoTransfer}}
<form method="post" action="{{$.RepoLink}}/action/accept_transfer?redirect_to={{$.RepoLink}}">
@ -100,7 +100,7 @@
</div><!-- end container -->
{{end}}
<div class="ui tabs container">
{{if not .Repository.IsBeingCreated}}
{{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}}
<div class="ui tabular stackable menu navbar">
{{if .Permission.CanRead $.UnitTypeCode}}
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL}}{{end}}">
@ -172,6 +172,14 @@
</div>
{{end}}
</div>
{{else if .Permission.IsAdmin}}
<div class="ui tabular stackable menu navbar">
<div class="right menu">
<a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings">
{{svg "octicon-tools"}} {{.i18n.Tr "repo.settings"}}
</a>
</div>
</div>
{{end}}
</div>
<div class="ui tabs divider"></div>

View File

@ -28,7 +28,7 @@
{{ $commitLink:= printf "%s/commit/%s" .RepoLink (PathEscape .LatestCommit.ID.String) }}
<span class="grey commit-summary" title="{{.LatestCommit.Summary}}"><span class="message-wrapper">{{RenderCommitMessageLinkSubject .LatestCommit.Message $.RepoLink $commitLink $.Repository.ComposeMetas}}</span>
{{if IsMultilineCommitMessage .LatestCommit.Message}}
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
<button class="ui button ellipsis-button" aria-expanded="false">...</button>
<pre class="commit-body" style="display: none;">{{RenderCommitBody .LatestCommit.Message $.RepoLink $.Repository.ComposeMetas}}</pre>
{{end}}
</span>

View File

@ -1,9 +1,11 @@
const {csrfToken} = window.config;
export function initRepoCommitButton() {
$('.commit-button').on('click', function (e) {
export function initRepoEllipsisButton() {
$('.ellipsis-button').on('click', function (e) {
e.preventDefault();
const expanded = $(this).attr('aria-expanded') === 'true';
$(this).parent().find('.commit-body').toggle();
$(this).attr('aria-expanded', String(!expanded));
});
}

View File

@ -36,7 +36,7 @@ import {
initRepoPullRequestMergeInstruction,
initRepoPullRequestReview,
} from './features/repo-issue.js';
import {initRepoCommitButton, initRepoCommitLastCommitLoader} from './features/repo-commit.js';
import {initRepoEllipsisButton, initRepoCommitLastCommitLoader} from './features/repo-commit.js';
import {
initFootLanguageMenu,
initGlobalButtonClickOnEnter,
@ -132,7 +132,7 @@ $(document).ready(() => {
initRepoBranchButton();
initRepoCodeView();
initRepoCommentForm();
initRepoCommitButton();
initRepoEllipsisButton();
initRepoCommitLastCommitLoader();
initRepoDiffConversationForm();
initRepoDiffFileViewToggle();

View File

@ -985,6 +985,13 @@ a.ui.card:hover,
margin: 0 6px;
}
.button.copy-commit-sha {
border: 1px solid var(--color-light-border);
margin-right: 3px;
padding: 6px 6px 4px;
background: var(--color-light);
}
.button.truncate {
display: inline-block;
max-width: 100%;
@ -2097,6 +2104,15 @@ table th[data-sortt-desc] {
display: flex !important;
}
.ellipsis-button {
padding: 0 5px 8px !important;
display: inline-block !important;
user-select: none !important;
font-weight: 600 !important;
line-height: 6px !important;
vertical-align: middle !important;
}
.truncated-item-name {
line-height: 2em;
white-space: nowrap;

View File

@ -1364,7 +1364,7 @@
text-align: center;
}
width: 175px;
width: 200px;
}
}