mirror of
https://github.com/go-gitea/gitea.git
synced 2025-04-18 00:47:48 -04:00
Merge branch 'main' into feature/bots
This commit is contained in:
commit
e65f69f52e
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
date: "2016-11-08T16:00:00+02:00"
|
date: "2023-01-07T22:03:00+01:00"
|
||||||
title: "Dokumentation"
|
title: "Dokumentation"
|
||||||
slug: "documentation"
|
slug: "documentation"
|
||||||
url: "/de-de/"
|
url: "/de-de/"
|
||||||
@ -27,11 +27,11 @@ Gitea ist ein [Gogs](http://gogs.io)-Fork.
|
|||||||
* 2 CPU Kerne und 1GB RAM sind für kleine Teams/Projekte ausreichend.
|
* 2 CPU Kerne und 1GB RAM sind für kleine Teams/Projekte ausreichend.
|
||||||
* Gitea sollte unter einem seperaten nicht-root Account auf UNIX-Systemen ausgeführt werden.
|
* Gitea sollte unter einem seperaten nicht-root Account auf UNIX-Systemen ausgeführt werden.
|
||||||
* Achtung: Gitea verwaltet die `~/.ssh/authorized_keys` Datei. Gitea unter einem normalen Benutzer auszuführen könnte dazu führen, dass dieser sich nicht mehr anmelden kann.
|
* Achtung: Gitea verwaltet die `~/.ssh/authorized_keys` Datei. Gitea unter einem normalen Benutzer auszuführen könnte dazu führen, dass dieser sich nicht mehr anmelden kann.
|
||||||
* [Git](https://git-scm.com/) Version 2.0 oder später wird benötigt.
|
* [Git](https://git-scm.com/) Version 2.0 oder aktueller wird benötigt.
|
||||||
* Wenn git >= 2.1.2. und [Git large file storage](https://git-lfs.github.com/) aktiviert ist, dann wird es auch in Gitea verwendbar sein.
|
* Wenn Git >= 2.1.2 und [Git LFS](https://git-lfs.github.com/) vorhanden ist, dann wird Git LFS Support automatisch für Gitea aktiviert.
|
||||||
* Wenn git >= 2.18, dann wird das Rendern von Commit-Graphen automatisch aktiviert.
|
* Wenn Git >= 2.18, dann wird das Rendern von Commit-Graphen automatisch aktiviert.
|
||||||
|
|
||||||
## Browser Unterstützung
|
## Browser Unterstützung
|
||||||
|
|
||||||
* Letzten 2 Versions von Chrome, Firefox, Safari und Edge
|
* Die neuesten zwei Versionen von Chrome, Firefox, Safari und Edge
|
||||||
* Firefox ESR
|
* Firefox ESR
|
||||||
|
@ -98,19 +98,31 @@ type Committer interface {
|
|||||||
// halfCommitter is a wrapper of Committer.
|
// halfCommitter is a wrapper of Committer.
|
||||||
// It can be closed early, but can't be committed early, it is useful for reusing a transaction.
|
// It can be closed early, but can't be committed early, it is useful for reusing a transaction.
|
||||||
type halfCommitter struct {
|
type halfCommitter struct {
|
||||||
Committer
|
committer Committer
|
||||||
|
committed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*halfCommitter) Commit() error {
|
func (c *halfCommitter) Commit() error {
|
||||||
// do nothing
|
c.committed = true
|
||||||
|
// should do nothing, and the parent committer will commit later
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *halfCommitter) Close() error {
|
||||||
|
if c.committed {
|
||||||
|
// it's "commit and close", should do nothing, and the parent committer will commit later
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// it's "rollback and close", let the parent committer rollback right now
|
||||||
|
return c.committer.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// TxContext represents a transaction Context,
|
// TxContext represents a transaction Context,
|
||||||
// it will reuse the existing transaction in the parent context or create a new one.
|
// it will reuse the existing transaction in the parent context or create a new one.
|
||||||
func TxContext(parentCtx context.Context) (*Context, Committer, error) {
|
func TxContext(parentCtx context.Context) (*Context, Committer, error) {
|
||||||
if sess, ok := inTransaction(parentCtx); ok {
|
if sess, ok := inTransaction(parentCtx); ok {
|
||||||
return newContext(parentCtx, sess, true), &halfCommitter{Committer: sess}, nil
|
return newContext(parentCtx, sess, true), &halfCommitter{committer: sess}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
@ -126,7 +138,12 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) {
|
|||||||
// this function will reuse it otherwise will create a new one and close it when finished.
|
// this function will reuse it otherwise will create a new one and close it when finished.
|
||||||
func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error {
|
func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error {
|
||||||
if sess, ok := inTransaction(parentCtx); ok {
|
if sess, ok := inTransaction(parentCtx); ok {
|
||||||
return f(newContext(parentCtx, sess, true))
|
err := f(newContext(parentCtx, sess, true))
|
||||||
|
if err != nil {
|
||||||
|
// rollback immediately, in case the caller ignores returned error and tries to commit the transaction.
|
||||||
|
_ = sess.Close()
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return txWithNoCheck(parentCtx, f)
|
return txWithNoCheck(parentCtx, f)
|
||||||
}
|
}
|
||||||
|
102
models/db/context_committer_test.go
Normal file
102
models/db/context_committer_test.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package db // it's not db_test, because this file is for testing the private type halfCommitter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockCommitter struct {
|
||||||
|
wants []string
|
||||||
|
gots []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMockCommitter(wants ...string) *MockCommitter {
|
||||||
|
return &MockCommitter{
|
||||||
|
wants: wants,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MockCommitter) Commit() error {
|
||||||
|
c.gots = append(c.gots, "commit")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MockCommitter) Close() error {
|
||||||
|
c.gots = append(c.gots, "close")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MockCommitter) Assert(t *testing.T) {
|
||||||
|
assert.Equal(t, c.wants, c.gots, "want operations %v, but got %v", c.wants, c.gots)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_halfCommitter(t *testing.T) {
|
||||||
|
/*
|
||||||
|
Do something like:
|
||||||
|
|
||||||
|
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
return committer.Commit()
|
||||||
|
*/
|
||||||
|
|
||||||
|
testWithCommitter := func(committer Committer, f func(committer Committer) error) {
|
||||||
|
if err := f(&halfCommitter{committer: committer}); err == nil {
|
||||||
|
committer.Commit()
|
||||||
|
}
|
||||||
|
committer.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("commit and close", func(t *testing.T) {
|
||||||
|
mockCommitter := NewMockCommitter("commit", "close")
|
||||||
|
|
||||||
|
testWithCommitter(mockCommitter, func(committer Committer) error {
|
||||||
|
defer committer.Close()
|
||||||
|
return committer.Commit()
|
||||||
|
})
|
||||||
|
|
||||||
|
mockCommitter.Assert(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("rollback and close", func(t *testing.T) {
|
||||||
|
mockCommitter := NewMockCommitter("close", "close")
|
||||||
|
|
||||||
|
testWithCommitter(mockCommitter, func(committer Committer) error {
|
||||||
|
defer committer.Close()
|
||||||
|
if true {
|
||||||
|
return fmt.Errorf("error")
|
||||||
|
}
|
||||||
|
return committer.Commit()
|
||||||
|
})
|
||||||
|
|
||||||
|
mockCommitter.Assert(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("close and commit", func(t *testing.T) {
|
||||||
|
mockCommitter := NewMockCommitter("close", "close")
|
||||||
|
|
||||||
|
testWithCommitter(mockCommitter, func(committer Committer) error {
|
||||||
|
committer.Close()
|
||||||
|
committer.Commit()
|
||||||
|
return fmt.Errorf("error")
|
||||||
|
})
|
||||||
|
|
||||||
|
mockCommitter.Assert(t)
|
||||||
|
})
|
||||||
|
}
|
@ -178,14 +178,25 @@ func newMailService() {
|
|||||||
|
|
||||||
// we want to warn if users use SMTP on a non-local IP;
|
// we want to warn if users use SMTP on a non-local IP;
|
||||||
// we might as well take the opportunity to check that it has an IP at all
|
// we might as well take the opportunity to check that it has an IP at all
|
||||||
ips := tryResolveAddr(MailService.SMTPAddr)
|
// This check is not needed for sendmail
|
||||||
if MailService.Protocol == "smtp" {
|
switch MailService.Protocol {
|
||||||
for _, ip := range ips {
|
case "sendmail":
|
||||||
if !ip.IsLoopback() {
|
var err error
|
||||||
log.Warn("connecting over insecure SMTP protocol to non-local address is not recommended")
|
MailService.SendmailArgs, err = shellquote.Split(sec.Key("SENDMAIL_ARGS").String())
|
||||||
break
|
if err != nil {
|
||||||
|
log.Error("Failed to parse Sendmail args: '%s' with error %v", sec.Key("SENDMAIL_ARGS").String(), err)
|
||||||
|
}
|
||||||
|
case "smtp", "smtps", "smtp+starttls", "smtp+unix":
|
||||||
|
ips := tryResolveAddr(MailService.SMTPAddr)
|
||||||
|
if MailService.Protocol == "smtp" {
|
||||||
|
for _, ip := range ips {
|
||||||
|
if !ip.IsLoopback() {
|
||||||
|
log.Warn("connecting over insecure SMTP protocol to non-local address is not recommended")
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "dummy": // just mention and do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
if MailService.From != "" {
|
if MailService.From != "" {
|
||||||
@ -214,14 +225,6 @@ func newMailService() {
|
|||||||
MailService.EnvelopeFrom = parsed.Address
|
MailService.EnvelopeFrom = parsed.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
if MailService.Protocol == "sendmail" {
|
|
||||||
var err error
|
|
||||||
MailService.SendmailArgs, err = shellquote.Split(sec.Key("SENDMAIL_ARGS").String())
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Failed to parse Sendmail args: %s with error %v", CustomConf, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Mail Service Enabled")
|
log.Info("Mail Service Enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{else if .IsSigned}}
|
{{else if .IsSigned}}
|
||||||
<div class="right stackable menu">
|
<div class="right stackable menu">
|
||||||
|
{{if EnableTimetracking}}
|
||||||
<a class="active-stopwatch-trigger item ui label {{if not .ActiveStopwatch}}hidden{{end}}" href="{{.ActiveStopwatch.IssueLink}}">
|
<a class="active-stopwatch-trigger item ui label {{if not .ActiveStopwatch}}hidden{{end}}" href="{{.ActiveStopwatch.IssueLink}}">
|
||||||
<span class="text">
|
<span class="text">
|
||||||
<span class="fitted item">
|
<span class="fitted item">
|
||||||
@ -115,6 +116,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<a href="{{AppSubUrl}}/notifications" class="item tooltip not-mobile" data-content="{{.locale.Tr "notifications"}}" aria-label="{{.locale.Tr "notifications"}}">
|
<a href="{{AppSubUrl}}/notifications" class="item tooltip not-mobile" data-content="{{.locale.Tr "notifications"}}" aria-label="{{.locale.Tr "notifications"}}">
|
||||||
<span class="text">
|
<span class="text">
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package main
|
package fuzz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
@ -24,6 +24,7 @@ export function initStopwatch() {
|
|||||||
trigger: 'click',
|
trigger: 'click',
|
||||||
maxWidth: 'none',
|
maxWidth: 'none',
|
||||||
interactive: true,
|
interactive: true,
|
||||||
|
hideOnClick: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// global stop watch (in the head_navbar), it should always work in any case either the EventSource or the PeriodicPoller is used.
|
// global stop watch (in the head_navbar), it should always work in any case either the EventSource or the PeriodicPoller is used.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user