Compare commits

..

No commits in common. "74225033413dc0f2b308bbe069f6d185b551e364" and "79e7a6ec1e14c820c8475173a37aee84f2f4f1e8" have entirely different histories.

66 changed files with 929 additions and 690 deletions

View File

@ -60,13 +60,13 @@ func main() {
// generate data
buf, err := generate()
if err != nil {
log.Fatalf("generate err: %v", err)
log.Fatal(err)
}
// write
err = os.WriteFile(*flagOut, buf, 0o644)
if err != nil {
log.Fatalf("WriteFile err: %v", err)
log.Fatal(err)
}
}

View File

@ -6,9 +6,9 @@ package cmd
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
@ -167,11 +167,11 @@ func runHookPreReceive(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
setup("hooks/pre-receive.log", c.Bool("debug"))
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
return fail(ctx, `Rejecting changes as Gitea environment not set.
return fail(`Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
}
@ -257,9 +257,14 @@ Gitea or set your environment appropriately.`, "")
hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs
hookOptions.RefFullNames = refFullNames
extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error)
statusCode, msg := private.HookPreReceive(ctx, username, reponame, hookOptions)
switch statusCode {
case http.StatusOK:
// no-op
case http.StatusInternalServerError:
return fail("Internal Server Error", msg)
default:
return fail(msg, "")
}
count = 0
lastline = 0
@ -280,9 +285,12 @@ Gitea or set your environment appropriately.`, "")
fmt.Fprintf(out, " Checking %d references\n", count)
extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error)
statusCode, msg := private.HookPreReceive(ctx, username, reponame, hookOptions)
switch statusCode {
case http.StatusInternalServerError:
return fail("Internal Server Error", msg)
case http.StatusForbidden:
return fail(msg, "")
}
} else if lastline > 0 {
fmt.Fprintf(out, "\n")
@ -301,7 +309,7 @@ func runHookPostReceive(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
setup("hooks/post-receive.log", c.Bool("debug"))
// First of all run update-server-info no matter what
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
@ -315,7 +323,7 @@ func runHookPostReceive(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
return fail(ctx, `Rejecting changes as Gitea environment not set.
return fail(`Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
}
@ -386,11 +394,11 @@ Gitea or set your environment appropriately.`, "")
hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs
hookOptions.RefFullNames = refFullNames
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
if extra.HasError() {
resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
if resp == nil {
_ = dWriter.Close()
hookPrintResults(results)
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
return fail("Internal Server Error", err)
}
wasEmpty = wasEmpty || resp.RepoWasEmpty
results = append(results, resp.Results...)
@ -401,9 +409,9 @@ Gitea or set your environment appropriately.`, "")
if count == 0 {
if wasEmpty && masterPushed {
// We need to tell the repo to reset the default branch to master
extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
if extra.HasError() {
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
if err != nil {
return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
}
}
fmt.Fprintf(out, "Processed %d references in total\n", total)
@ -419,11 +427,11 @@ Gitea or set your environment appropriately.`, "")
fmt.Fprintf(out, " Processing %d references\n", count)
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
if resp == nil {
_ = dWriter.Close()
hookPrintResults(results)
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
return fail("Internal Server Error", err)
}
wasEmpty = wasEmpty || resp.RepoWasEmpty
results = append(results, resp.Results...)
@ -432,9 +440,9 @@ Gitea or set your environment appropriately.`, "")
if wasEmpty && masterPushed {
// We need to tell the repo to reset the default branch to master
extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
if extra.HasError() {
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
if err != nil {
return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
}
}
_ = dWriter.Close()
@ -477,22 +485,22 @@ func pushOptions() map[string]string {
}
func runHookProcReceive(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
setup("hooks/proc-receive.log", c.Bool("debug"))
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
return fail(ctx, `Rejecting changes as Gitea environment not set.
return fail(`Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
}
return nil
}
ctx, cancel := installSignals()
defer cancel()
if git.CheckGitVersionAtLeast("2.29") != nil {
return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.")
return fail("Internal Server Error", "git not support proc-receive.")
}
reader := bufio.NewReader(os.Stdin)
@ -507,7 +515,7 @@ Gitea or set your environment appropriately.`, "")
// H: PKT-LINE(version=1\0push-options...)
// H: flush-pkt
rs, err := readPktLine(ctx, reader, pktLineTypeData)
rs, err := readPktLine(reader, pktLineTypeData)
if err != nil {
return err
}
@ -522,19 +530,19 @@ Gitea or set your environment appropriately.`, "")
index := bytes.IndexByte(rs.Data, byte(0))
if index >= len(rs.Data) {
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
return fail("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
}
if index < 0 {
if len(rs.Data) == 10 && rs.Data[9] == '\n' {
index = 9
} else {
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
return fail("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
}
}
if string(rs.Data[0:index]) != VersionHead {
return fail(ctx, "Protocol: version error", "Received unsupported version: %s", string(rs.Data[0:index]))
return fail("Internal Server Error", "Received unsupported version: %s", string(rs.Data[0:index]))
}
requestOptions = strings.Split(string(rs.Data[index+1:]), " ")
@ -547,17 +555,17 @@ Gitea or set your environment appropriately.`, "")
}
response = append(response, '\n')
_, err = readPktLine(ctx, reader, pktLineTypeFlush)
_, err = readPktLine(reader, pktLineTypeFlush)
if err != nil {
return err
}
err = writeDataPktLine(ctx, os.Stdout, response)
err = writeDataPktLine(os.Stdout, response)
if err != nil {
return err
}
err = writeFlushPktLine(ctx, os.Stdout)
err = writeFlushPktLine(os.Stdout)
if err != nil {
return err
}
@ -580,7 +588,7 @@ Gitea or set your environment appropriately.`, "")
for {
// note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
rs, err = readPktLine(reader, pktLineTypeUnknow)
if err != nil {
return err
}
@ -601,7 +609,7 @@ Gitea or set your environment appropriately.`, "")
if hasPushOptions {
for {
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
rs, err = readPktLine(reader, pktLineTypeUnknow)
if err != nil {
return err
}
@ -618,9 +626,9 @@ Gitea or set your environment appropriately.`, "")
}
// 3. run hook
resp, extra := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "HookProcReceive failed: %v", extra.Error)
resp, err := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
if err != nil {
return fail("Internal Server Error", "run proc-receive hook failed :%v", err)
}
// 4. response result to service
@ -641,7 +649,7 @@ Gitea or set your environment appropriately.`, "")
for _, rs := range resp.Results {
if len(rs.Err) > 0 {
err = writeDataPktLine(ctx, os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
err = writeDataPktLine(os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
if err != nil {
return err
}
@ -649,43 +657,43 @@ Gitea or set your environment appropriately.`, "")
}
if rs.IsNotMatched {
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
if err != nil {
return err
}
err = writeDataPktLine(ctx, os.Stdout, []byte("option fall-through"))
err = writeDataPktLine(os.Stdout, []byte("option fall-through"))
if err != nil {
return err
}
continue
}
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
if err != nil {
return err
}
err = writeDataPktLine(ctx, os.Stdout, []byte("option refname "+rs.Ref))
err = writeDataPktLine(os.Stdout, []byte("option refname "+rs.Ref))
if err != nil {
return err
}
if rs.OldOID != git.EmptySHA {
err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
err = writeDataPktLine(os.Stdout, []byte("option old-oid "+rs.OldOID))
if err != nil {
return err
}
}
err = writeDataPktLine(ctx, os.Stdout, []byte("option new-oid "+rs.NewOID))
err = writeDataPktLine(os.Stdout, []byte("option new-oid "+rs.NewOID))
if err != nil {
return err
}
if rs.IsForcePush {
err = writeDataPktLine(ctx, os.Stdout, []byte("option forced-update"))
err = writeDataPktLine(os.Stdout, []byte("option forced-update"))
if err != nil {
return err
}
}
}
err = writeFlushPktLine(ctx, os.Stdout)
err = writeFlushPktLine(os.Stdout)
return err
}
@ -710,7 +718,7 @@ type gitPktLine struct {
Data []byte
}
func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
var (
err error
r *gitPktLine
@ -721,33 +729,33 @@ func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType)
for i := 0; i < 4; i++ {
lengthBytes[i], err = in.ReadByte()
if err != nil {
return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err)
return nil, fail("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
}
}
r = new(gitPktLine)
r.Length, err = strconv.ParseUint(string(lengthBytes), 16, 32)
if err != nil {
return nil, fail(ctx, "Protocol: format parse error", "Pkt-Line format is wrong :%v", err)
return nil, fail("Internal Server Error", "Pkt-Line format is wrong :%v", err)
}
if r.Length == 0 {
if requestType == pktLineTypeData {
return nil, fail(ctx, "Protocol: format data error", "Pkt-Line format is wrong")
return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
}
r.Type = pktLineTypeFlush
return r, nil
}
if r.Length <= 4 || r.Length > 65520 || requestType == pktLineTypeFlush {
return nil, fail(ctx, "Protocol: format length error", "Pkt-Line format is wrong")
return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
}
r.Data = make([]byte, r.Length-4)
for i := range r.Data {
r.Data[i], err = in.ReadByte()
if err != nil {
return nil, fail(ctx, "Protocol: data error", "Pkt-Line: read stdin failed : %v", err)
return nil, fail("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
}
}
@ -756,15 +764,19 @@ func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType)
return r, nil
}
func writeFlushPktLine(ctx context.Context, out io.Writer) error {
func writeFlushPktLine(out io.Writer) error {
l, err := out.Write([]byte("0000"))
if err != nil || l != 4 {
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
if err != nil {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
}
if l != 4 {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
}
return nil
}
func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error {
func writeDataPktLine(out io.Writer, data []byte) error {
hexchar := []byte("0123456789abcdef")
hex := func(n uint64) byte {
return hexchar[(n)&15]
@ -778,13 +790,19 @@ func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error {
tmp[3] = hex(length)
lr, err := out.Write(tmp)
if err != nil || lr != 4 {
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
if err != nil {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
}
if lr != 4 {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
}
lr, err = out.Write(data)
if err != nil || int(length-4) != lr {
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
if err != nil {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
}
if int(length-4) != lr {
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
}
return nil

View File

@ -6,7 +6,6 @@ package cmd
import (
"bufio"
"bytes"
"context"
"strings"
"testing"
@ -15,28 +14,27 @@ import (
func TestPktLine(t *testing.T) {
// test read
ctx := context.Background()
s := strings.NewReader("0000")
r := bufio.NewReader(s)
result, err := readPktLine(ctx, r, pktLineTypeFlush)
result, err := readPktLine(r, pktLineTypeFlush)
assert.NoError(t, err)
assert.Equal(t, pktLineTypeFlush, result.Type)
s = strings.NewReader("0006a\n")
r = bufio.NewReader(s)
result, err = readPktLine(ctx, r, pktLineTypeData)
result, err = readPktLine(r, pktLineTypeData)
assert.NoError(t, err)
assert.Equal(t, pktLineTypeData, result.Type)
assert.Equal(t, []byte("a\n"), result.Data)
// test write
w := bytes.NewBuffer([]byte{})
err = writeFlushPktLine(ctx, w)
err = writeFlushPktLine(w)
assert.NoError(t, err)
assert.Equal(t, []byte("0000"), w.Bytes())
w.Reset()
err = writeDataPktLine(ctx, w, []byte("a\nb"))
err = writeDataPktLine(w, []byte("a\nb"))
assert.NoError(t, err)
assert.Equal(t, []byte("0007a\nb"), w.Bytes())
}

View File

@ -64,12 +64,11 @@ func runKeys(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, false)
setup("keys.log", false)
authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content)
// do not use handleCliResponseExtra or cli.NewExitError, if it exists immediately, it breaks some tests like Test_CmdKeys
if extra.Error != nil {
return extra.Error
authorizedString, err := private.AuthorizedPublicKeyByContent(ctx, content)
if err != nil {
return err
}
fmt.Println(strings.TrimSpace(authorizedString))
return nil

View File

@ -5,6 +5,7 @@ package cmd
import (
"fmt"
"net/http"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
@ -42,10 +43,13 @@ func runSendMail(c *cli.Context) error {
}
}
respText, extra := private.SendEmail(ctx, subject, body, nil)
if extra.HasError() {
return handleCliResponseExtra(extra)
status, message := private.SendEmail(ctx, subject, body, nil)
if status != http.StatusOK {
fmt.Printf("error: %s\n", message)
return nil
}
_, _ = fmt.Printf("Sent %s email(s) to all users\n", respText)
fmt.Printf("Success: %s\n", message)
return nil
}

View File

@ -4,6 +4,8 @@
package cmd
import (
"fmt"
"net/http"
"os"
"time"
@ -101,34 +103,57 @@ func runShutdown(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
extra := private.Shutdown(ctx)
return handleCliResponseExtra(extra)
setup("manager", c.Bool("debug"))
statusCode, msg := private.Shutdown(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
func runRestart(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
extra := private.Restart(ctx)
return handleCliResponseExtra(extra)
setup("manager", c.Bool("debug"))
statusCode, msg := private.Restart(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
func runFlushQueues(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
extra := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
return handleCliResponseExtra(extra)
setup("manager", c.Bool("debug"))
statusCode, msg := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
func runProcesses(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
extra := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
return handleCliResponseExtra(extra)
setup("manager", c.Bool("debug"))
statusCode, msg := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
return nil
}

View File

@ -5,6 +5,7 @@ package cmd
import (
"fmt"
"net/http"
"os"
"code.gitea.io/gitea/modules/log"
@ -190,25 +191,27 @@ var (
)
func runRemoveLogger(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
setup("manager", c.Bool("debug"))
group := c.String("group")
if len(group) == 0 {
group = log.DEFAULT
}
name := c.Args().First()
extra := private.RemoveLogger(ctx, group, name)
return handleCliResponseExtra(extra)
}
func runAddSMTPLogger(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
statusCode, msg := private.RemoveLogger(ctx, group, name)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
func runAddSMTPLogger(c *cli.Context) error {
setup("manager", c.Bool("debug"))
vals := map[string]interface{}{}
mode := "smtp"
if c.IsSet("host") {
@ -239,10 +242,7 @@ func runAddSMTPLogger(c *cli.Context) error {
}
func runAddConnLogger(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
setup("manager", c.Bool("debug"))
vals := map[string]interface{}{}
mode := "conn"
vals["net"] = "tcp"
@ -269,10 +269,7 @@ func runAddConnLogger(c *cli.Context) error {
}
func runAddFileLogger(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
setup("manager", c.Bool("debug"))
vals := map[string]interface{}{}
mode := "file"
if c.IsSet("filename") {
@ -302,10 +299,7 @@ func runAddFileLogger(c *cli.Context) error {
}
func runAddConsoleLogger(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
setup("manager", c.Bool("debug"))
vals := map[string]interface{}{}
mode := "console"
if c.IsSet("stderr") && c.Bool("stderr") {
@ -344,17 +338,28 @@ func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) e
ctx, cancel := installSignals()
defer cancel()
extra := private.AddLogger(ctx, group, name, mode, vals)
return handleCliResponseExtra(extra)
statusCode, msg := private.AddLogger(ctx, group, name, mode, vals)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
func runPauseLogging(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
userMsg := private.PauseLogging(ctx)
_, _ = fmt.Fprintln(os.Stdout, userMsg)
setup("manager", c.Bool("debug"))
statusCode, msg := private.PauseLogging(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
@ -362,9 +367,14 @@ func runResumeLogging(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
userMsg := private.ResumeLogging(ctx)
_, _ = fmt.Fprintln(os.Stdout, userMsg)
setup("manager", c.Bool("debug"))
statusCode, msg := private.ResumeLogging(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
@ -372,17 +382,28 @@ func runReleaseReopenLogging(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
userMsg := private.ReleaseReopenLogging(ctx)
_, _ = fmt.Fprintln(os.Stdout, userMsg)
setup("manager", c.Bool("debug"))
statusCode, msg := private.ReleaseReopenLogging(ctx)
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}
func runSetLogSQL(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setup(ctx, c.Bool("debug"))
setup("manager", c.Bool("debug"))
extra := private.SetLogSQL(ctx, !c.Bool("off"))
return handleCliResponseExtra(extra)
statusCode, msg := private.SetLogSQL(ctx, !c.Bool("off"))
switch statusCode {
case http.StatusInternalServerError:
return fail("InternalServerError", msg)
}
fmt.Fprintln(os.Stdout, msg)
return nil
}

View File

@ -4,8 +4,11 @@
package cmd
import (
"errors"
"net/http"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
@ -57,7 +60,7 @@ func runRestoreRepository(c *cli.Context) error {
if s := c.String("units"); s != "" {
units = strings.Split(s, ",")
}
extra := private.RestoreRepo(
statusCode, errStr := private.RestoreRepo(
ctx,
c.String("repo_dir"),
c.String("owner_name"),
@ -65,5 +68,10 @@ func runRestoreRepository(c *cli.Context) error {
units,
c.Bool("validation"),
)
return handleCliResponseExtra(extra)
if statusCode == http.StatusOK {
return nil
}
log.Fatal("Failed to restore repository: %v", errStr)
return errors.New(errStr)
}

View File

@ -7,6 +7,7 @@ package cmd
import (
"context"
"fmt"
"net/http"
"net/url"
"os"
"os/exec"
@ -15,7 +16,6 @@ import (
"strconv"
"strings"
"time"
"unicode"
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
@ -55,7 +55,7 @@ var CmdServ = cli.Command{
},
}
func setup(ctx context.Context, debug bool) {
func setup(logPath string, debug bool) {
_ = log.DelLogger("console")
if debug {
_ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`)
@ -72,15 +72,15 @@ func setup(ctx context.Context, debug bool) {
// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
if _, err := os.Stat(setting.RepoRootPath); err != nil {
if os.IsNotExist(err) {
_ = fail(ctx, "Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath)
_ = fail("Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath)
} else {
_ = fail(ctx, "Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
_ = fail("Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
}
return
}
if err := git.InitSimple(context.Background()); err != nil {
_ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err)
_ = fail("Failed to init git", "Failed to init git, err: %v", err)
}
}
@ -94,54 +94,32 @@ var (
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)
// fail prints message to stdout, it's mainly used for git serv and git hook commands.
// The output will be passed to git client and shown to user.
func fail(ctx context.Context, userMessage, logMsgFmt string, args ...interface{}) error {
if userMessage == "" {
userMessage = "Internal Server Error (no specific error)"
}
func fail(userMessage, logMessage string, args ...interface{}) error {
// There appears to be a chance to cause a zombie process and failure to read the Exit status
// if nothing is outputted on stdout.
_, _ = fmt.Fprintln(os.Stdout, "")
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage)
if logMsgFmt != "" {
logMsg := fmt.Sprintf(logMsgFmt, args...)
if len(logMessage) > 0 {
if !setting.IsProd {
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", logMsg)
_, _ = fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
}
if userMessage != "" {
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
logMsg = userMessage + " " + logMsg
} else {
logMsg = userMessage + ". " + logMsg
}
}
_ = private.SSHLog(ctx, true, logMsg)
}
ctx, cancel := installSignals()
defer cancel()
if len(logMessage) > 0 {
_ = private.SSHLog(ctx, true, fmt.Sprintf(logMessage+": ", args...))
}
return cli.NewExitError("", 1)
}
// handleCliResponseExtra handles the extra response from the cli sub-commands
// If there is a user message it will be printed to stdout
// If the command failed it will return an error (the error will be printed by cli framework)
func handleCliResponseExtra(extra private.ResponseExtra) error {
if extra.UserMsg != "" {
_, _ = fmt.Fprintln(os.Stdout, extra.UserMsg)
}
if extra.HasError() {
return cli.NewExitError(extra.Error, 1)
}
return nil
}
func runServ(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
// FIXME: This needs to internationalised
setup(ctx, c.Bool("debug"))
setup("serv.log", c.Bool("debug"))
if setting.SSH.Disabled {
println("Gitea: SSH has been disabled")
@ -157,18 +135,18 @@ func runServ(c *cli.Context) error {
keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 || keys[0] != "key" {
return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args()[0])
return fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
}
keyID, err := strconv.ParseInt(keys[1], 10, 64)
if err != nil {
return fail(ctx, "Key ID parsing error", "Invalid key argument: %s", c.Args()[1])
return fail("Key ID format error", "Invalid key argument: %s", c.Args()[1])
}
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
if len(cmd) == 0 {
key, user, err := private.ServNoCommand(ctx, keyID)
if err != nil {
return fail(ctx, "Key check failed", "Failed to check provided key: %v", err)
return fail("Internal error", "Failed to check provided key: %v", err)
}
switch key.Type {
case asymkey_model.KeyTypeDeploy:
@ -186,7 +164,7 @@ func runServ(c *cli.Context) error {
words, err := shellquote.Split(cmd)
if err != nil {
return fail(ctx, "Error parsing arguments", "Failed to parse arguments: %v", err)
return fail("Error parsing arguments", "Failed to parse arguments: %v", err)
}
if len(words) < 2 {
@ -197,7 +175,7 @@ func runServ(c *cli.Context) error {
return nil
}
}
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
return fail("Too few arguments", "Too few arguments in cmd: %s", cmd)
}
verb := words[0]
@ -209,7 +187,7 @@ func runServ(c *cli.Context) error {
var lfsVerb string
if verb == lfsAuthenticateVerb {
if !setting.LFS.StartServer {
return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
return fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
}
if len(words) > 2 {
@ -222,37 +200,37 @@ func runServ(c *cli.Context) error {
rr := strings.SplitN(repoPath, "/", 2)
if len(rr) != 2 {
return fail(ctx, "Invalid repository path", "Invalid repository path: %v", repoPath)
return fail("Invalid repository path", "Invalid repository path: %v", repoPath)
}
username := strings.ToLower(rr[0])
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
if alphaDashDotPattern.MatchString(reponame) {
return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame)
return fail("Invalid repo name", "Invalid repo name: %s", reponame)
}
if c.Bool("enable-pprof") {
if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
return fail(ctx, "Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
return fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
}
stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
if err != nil {
return fail(ctx, "Unable to start CPU profiler", "Unable to start CPU profile: %v", err)
return fail("Internal Server Error", "Unable to start CPU profile: %v", err)
}
defer func() {
stopCPUProfiler()
err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
if err != nil {
_ = fail(ctx, "Unable to dump Mem profile", "Unable to dump Mem Profile: %v", err)
_ = fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
}
}()
}
requestedMode, has := allowedCommands[verb]
if !has {
return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
return fail("Unknown git command", "Unknown git command %s", verb)
}
if verb == lfsAuthenticateVerb {
@ -261,13 +239,20 @@ func runServ(c *cli.Context) error {
} else if lfsVerb == "download" {
requestedMode = perm.AccessModeRead
} else {
return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
return fail("Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
}
}
results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
results, err := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
if err != nil {
if private.IsErrServCommand(err) {
errServCommand := err.(private.ErrServCommand)
if errServCommand.StatusCode != http.StatusInternalServerError {
return fail("Unauthorized", "%s", errServCommand.Error())
}
return fail("Internal Server Error", "%s", errServCommand.Error())
}
return fail("Internal Server Error", "%s", err.Error())
}
// LFS token authentication
@ -289,7 +274,7 @@ func runServ(c *cli.Context) error {
// Sign and get the complete encoded token as a string using the secret
tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
if err != nil {
return fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
return fail("Internal error", "Failed to sign JWT token: %v", err)
}
tokenAuthentication := &git_model.LFSTokenResponse{
@ -301,7 +286,7 @@ func runServ(c *cli.Context) error {
enc := json.NewEncoder(os.Stdout)
err = enc.Encode(tokenAuthentication)
if err != nil {
return fail(ctx, "Failed to encode LFS json response", "Failed to encode LFS json response: %v", err)
return fail("Internal error", "Failed to encode LFS json response: %v", err)
}
return nil
}
@ -347,13 +332,13 @@ func runServ(c *cli.Context) error {
gitcmd.Env = append(gitcmd.Env, git.CommonCmdServEnvs()...)
if err = gitcmd.Run(); err != nil {
return fail(ctx, "Failed to execute git command", "Failed to execute git command: %v", err)
return fail("Internal error", "Failed to execute git command: %v", err)
}
// Update user key activity.
if results.KeyID > 0 {
if err = private.UpdatePublicKeyInRepo(ctx, results.KeyID, results.RepoID); err != nil {
return fail(ctx, "Failed to update public key", "UpdatePublicKeyInRepo: %v", err)
return fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
}
}

View File

@ -1238,10 +1238,6 @@ ROUTER = console
;;
;; Whether to enable a Service Worker to cache frontend assets
;USE_SERVICE_WORKER = false
;;
;; Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
;; A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
;ONLY_SHOW_RELEVANT_REPOS = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -226,13 +226,11 @@ The following configuration set `Content-Type: application/vnd.android.package-a
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
- `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
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`: **false**: Whether to enable a Service Worker to cache frontend assets.
- `ONLY_SHOW_RELEVANT_REPOS`: **false** Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
### UI - Admin (`ui.admin`)

View File

@ -8,7 +8,6 @@ import (
"bytes"
"context"
"crypto/tls"
"fmt"
"io"
"net"
"net/http"
@ -69,11 +68,6 @@ func (r *Request) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *Re
return r
}
func (r *Request) SetReadWriteTimeout(readWriteTimeout time.Duration) *Request {
r.setting.ReadWriteTimeout = readWriteTimeout
return r
}
// SetTLSClientConfig sets tls connection configurations if visiting https url.
func (r *Request) SetTLSClientConfig(config *tls.Config) *Request {
r.setting.TLSClientConfig = config
@ -144,11 +138,11 @@ func (r *Request) getResponse() (*http.Response, error) {
r.Body(paramBody)
}
var err error
r.req.URL, err = url.Parse(r.url)
url, err := url.Parse(r.url)
if err != nil {
return nil, err
}
r.req.URL = url
trans := r.setting.Transport
if trans == nil {
@ -200,7 +194,3 @@ func TimeoutDialer(cTimeout time.Duration) func(ctx context.Context, net, addr s
return conn, nil
}
}
func (r *Request) GoString() string {
return fmt.Sprintf("%s %s", r.req.Method, r.url)
}

View File

@ -5,11 +5,14 @@ package private
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
@ -96,46 +99,126 @@ type HookProcReceiveRefResult struct {
}
// HookPreReceive check whether the provided commits are allowed
func HookPreReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) ResponseExtra {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName))
req := newInternalRequest(ctx, reqURL, "POST", opts)
req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
_, extra := requestJSONResp(req, &responseText{})
return extra
func HookPreReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (int, string) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s",
url.PathEscape(ownerName),
url.PathEscape(repoName),
)
req := newInternalRequest(ctx, reqURL, "POST")
req = req.Header("Content-Type", "application/json")
jsonBytes, _ := json.Marshal(opts)
req.Body(jsonBytes)
req.SetTimeout(60*time.Second, time.Duration(60+len(opts.OldCommitIDs))*time.Second)
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, ""
}
// HookPostReceive updates services and users
func HookPostReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookPostReceiveResult, ResponseExtra) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/post-receive/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName))
req := newInternalRequest(ctx, reqURL, "POST", opts)
req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
return requestJSONResp(req, &HookPostReceiveResult{})
func HookPostReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookPostReceiveResult, string) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/post-receive/%s/%s",
url.PathEscape(ownerName),
url.PathEscape(repoName),
)
req := newInternalRequest(ctx, reqURL, "POST")
req = req.Header("Content-Type", "application/json")
req.SetTimeout(60*time.Second, time.Duration(60+len(opts.OldCommitIDs))*time.Second)
jsonBytes, _ := json.Marshal(opts)
req.Body(jsonBytes)
resp, err := req.Response()
if err != nil {
return nil, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, decodeJSONError(resp).Err
}
res := &HookPostReceiveResult{}
_ = json.NewDecoder(resp.Body).Decode(res)
return res, ""
}
// HookProcReceive proc-receive hook
func HookProcReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookProcReceiveResult, ResponseExtra) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/proc-receive/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName))
func HookProcReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookProcReceiveResult, error) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/proc-receive/%s/%s",
url.PathEscape(ownerName),
url.PathEscape(repoName),
)
req := newInternalRequest(ctx, reqURL, "POST", opts)
req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
return requestJSONResp(req, &HookProcReceiveResult{})
req := newInternalRequest(ctx, reqURL, "POST")
req = req.Header("Content-Type", "application/json")
req.SetTimeout(60*time.Second, time.Duration(60+len(opts.OldCommitIDs))*time.Second)
jsonBytes, _ := json.Marshal(opts)
req.Body(jsonBytes)
resp, err := req.Response()
if err != nil {
return nil, fmt.Errorf("Unable to contact gitea: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New(decodeJSONError(resp).Err)
}
res := &HookProcReceiveResult{}
_ = json.NewDecoder(resp.Body).Decode(res)
return res, nil
}
// SetDefaultBranch will set the default branch to the provided branch for the provided repository
func SetDefaultBranch(ctx context.Context, ownerName, repoName, branch string) ResponseExtra {
func SetDefaultBranch(ctx context.Context, ownerName, repoName, branch string) error {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/set-default-branch/%s/%s/%s",
url.PathEscape(ownerName),
url.PathEscape(repoName),
url.PathEscape(branch),
)
req := newInternalRequest(ctx, reqURL, "POST")
return requestJSONUserMsg(req, "")
req = req.Header("Content-Type", "application/json")
req.SetTimeout(60*time.Second, 60*time.Second)
resp, err := req.Response()
if err != nil {
return fmt.Errorf("Unable to contact gitea: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("Error returned from gitea: %v", decodeJSONError(resp).Err)
}
return nil
}
// SSHLog sends ssh error log response
func SSHLog(ctx context.Context, isErr bool, msg string) error {
reqURL := setting.LocalURL + "api/internal/ssh/log"
req := newInternalRequest(ctx, reqURL, "POST", &SSHLogOption{IsError: isErr, Message: msg})
_, extra := requestJSONResp(req, &responseText{})
return extra.Error
req := newInternalRequest(ctx, reqURL, "POST")
req = req.Header("Content-Type", "application/json")
jsonBytes, _ := json.Marshal(&SSHLogOption{
IsError: isErr,
Message: msg,
})
req.Body(jsonBytes)
req.SetTimeout(60*time.Second, 60*time.Second)
resp, err := req.Response()
if err != nil {
return fmt.Errorf("unable to contact gitea: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("Error returned from gitea: %v", decodeJSONError(resp).Err)
}
return nil
}

View File

@ -11,7 +11,6 @@ import (
"net/http"
"os"
"strings"
"time"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/json"
@ -20,10 +19,29 @@ import (
"code.gitea.io/gitea/modules/setting"
)
// Response is used for internal request response (for user message and error message)
func newRequest(ctx context.Context, url, method, sourceIP string) *httplib.Request {
if setting.InternalToken == "" {
log.Fatal(`The INTERNAL_TOKEN setting is missing from the configuration file: %q.
Ensure you are running in the correct environment or set the correct configuration file with -c.`, setting.CustomConf)
}
return httplib.NewRequest(url, method).
SetContext(ctx).
Header("X-Real-IP", sourceIP).
Header("Authorization", fmt.Sprintf("Bearer %s", setting.InternalToken))
}
// Response internal request response
type Response struct {
Err string `json:"err,omitempty"` // server-side error log message, it won't be exposed to end users
UserMsg string `json:"user_msg,omitempty"` // meaningful error message for end users, it will be shown in git client's output.
Err string `json:"err"`
}
func decodeJSONError(resp *http.Response) *Response {
var res Response
err := json.NewDecoder(resp.Body).Decode(&res)
if err != nil {
res.Err = err.Error()
}
return &res
}
func getClientIP() string {
@ -34,21 +52,11 @@ func getClientIP() string {
return strings.Fields(sshConnEnv)[0]
}
func newInternalRequest(ctx context.Context, url, method string, body ...any) *httplib.Request {
if setting.InternalToken == "" {
log.Fatal(`The INTERNAL_TOKEN setting is missing from the configuration file: %q.
Ensure you are running in the correct environment or set the correct configuration file with -c.`, setting.CustomConf)
}
req := httplib.NewRequest(url, method).
SetContext(ctx).
Header("X-Real-IP", getClientIP()).
Header("Authorization", fmt.Sprintf("Bearer %s", setting.InternalToken)).
SetTLSClientConfig(&tls.Config{
InsecureSkipVerify: true,
ServerName: setting.Domain,
})
func newInternalRequest(ctx context.Context, url, method string) *httplib.Request {
req := newRequest(ctx, url, method, getClientIP()).SetTLSClientConfig(&tls.Config{
InsecureSkipVerify: true,
ServerName: setting.Domain,
})
if setting.Protocol == setting.HTTPUnix {
req.SetTransport(&http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
@ -82,15 +90,5 @@ Ensure you are running in the correct environment or set the correct configurati
},
})
}
if len(body) == 1 {
req.Header("Content-Type", "application/json")
jsonBytes, _ := json.Marshal(body[0])
req.Body(jsonBytes)
} else if len(body) > 1 {
log.Fatal("Too many arguments for newInternalRequest")
}
req.SetTimeout(10*time.Second, 60*time.Second)
return req
}

View File

@ -6,6 +6,8 @@ package private
import (
"context"
"fmt"
"io"
"net/http"
"code.gitea.io/gitea/modules/setting"
)
@ -14,18 +16,39 @@ import (
func UpdatePublicKeyInRepo(ctx context.Context, keyID, repoID int64) error {
// Ask for running deliver hook and test pull request tasks.
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d/update/%d", keyID, repoID)
req := newInternalRequest(ctx, reqURL, "POST")
_, extra := requestJSONResp(req, &responseText{})
return extra.Error
resp, err := newInternalRequest(ctx, reqURL, "POST").Response()
if err != nil {
return err
}
defer resp.Body.Close()
// All 2XX status codes are accepted and others will return an error
if resp.StatusCode/100 != 2 {
return fmt.Errorf("Failed to update public key: %s", decodeJSONError(resp).Err)
}
return nil
}
// AuthorizedPublicKeyByContent searches content as prefix (leak e-mail part)
// and returns public key found.
func AuthorizedPublicKeyByContent(ctx context.Context, content string) (string, ResponseExtra) {
func AuthorizedPublicKeyByContent(ctx context.Context, content string) (string, error) {
// Ask for running deliver hook and test pull request tasks.
reqURL := setting.LocalURL + "api/internal/ssh/authorized_keys"
req := newInternalRequest(ctx, reqURL, "POST")
req.Param("content", content)
resp, extra := requestJSONResp(req, &responseText{})
return resp.Text, extra
resp, err := req.Response()
if err != nil {
return "", err
}
defer resp.Body.Close()
// All 2XX status codes are accepted and others will return an error
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("Failed to update public key: %s", decodeJSONError(resp).Err)
}
bs, err := io.ReadAll(resp.Body)
return string(bs), err
}

View File

@ -5,7 +5,11 @@ package private
import (
"context"
"fmt"
"io"
"net/http"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
@ -17,18 +21,38 @@ type Email struct {
}
// SendEmail calls the internal SendEmail function
//
// It accepts a list of usernames.
// If DB contains these users it will send the email to them.
// If to list == nil, it's supposed to send emails to every user present in DB
func SendEmail(ctx context.Context, subject, message string, to []string) (string, ResponseExtra) {
//
// If to list == nil its supposed to send an email to every
// user present in DB
func SendEmail(ctx context.Context, subject, message string, to []string) (int, string) {
reqURL := setting.LocalURL + "api/internal/mail/send"
req := newInternalRequest(ctx, reqURL, "POST", Email{
req := newInternalRequest(ctx, reqURL, "POST")
req = req.Header("Content-Type", "application/json")
jsonBytes, _ := json.Marshal(Email{
Subject: subject,
Message: message,
To: to,
})
req.Body(jsonBytes)
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
resp, extra := requestJSONResp(req, &responseText{})
return resp.Text, extra
body, err := io.ReadAll(resp.Body)
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Response body error: %v", err.Error())
}
users := fmt.Sprintf("%d", len(to))
if len(to) == 0 {
users = "all"
}
return http.StatusOK, fmt.Sprintf("Sent %s email(s) to %s users", body, users)
}

View File

@ -12,21 +12,44 @@ import (
"strconv"
"time"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
// Shutdown calls the internal shutdown function
func Shutdown(ctx context.Context) ResponseExtra {
func Shutdown(ctx context.Context) (int, string) {
reqURL := setting.LocalURL + "api/internal/manager/shutdown"
req := newInternalRequest(ctx, reqURL, "POST")
return requestJSONUserMsg(req, "Shutting down")
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, "Shutting down"
}
// Restart calls the internal restart function
func Restart(ctx context.Context) ResponseExtra {
func Restart(ctx context.Context) (int, string) {
reqURL := setting.LocalURL + "api/internal/manager/restart"
req := newInternalRequest(ctx, reqURL, "POST")
return requestJSONUserMsg(req, "Restarting")
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, "Restarting"
}
// FlushOptions represents the options for the flush call
@ -36,41 +59,102 @@ type FlushOptions struct {
}
// FlushQueues calls the internal flush-queues function
func FlushQueues(ctx context.Context, timeout time.Duration, nonBlocking bool) ResponseExtra {
func FlushQueues(ctx context.Context, timeout time.Duration, nonBlocking bool) (int, string) {
reqURL := setting.LocalURL + "api/internal/manager/flush-queues"
req := newInternalRequest(ctx, reqURL, "POST", FlushOptions{Timeout: timeout, NonBlocking: nonBlocking})
req := newInternalRequest(ctx, reqURL, "POST")
if timeout > 0 {
req.SetReadWriteTimeout(timeout + 10*time.Second)
req.SetTimeout(timeout+10*time.Second, timeout+10*time.Second)
}
return requestJSONUserMsg(req, "Flushed")
req = req.Header("Content-Type", "application/json")
jsonBytes, _ := json.Marshal(FlushOptions{
Timeout: timeout,
NonBlocking: nonBlocking,
})
req.Body(jsonBytes)
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, "Flushed"
}
// PauseLogging pauses logging
func PauseLogging(ctx context.Context) ResponseExtra {
func PauseLogging(ctx context.Context) (int, string) {
reqURL := setting.LocalURL + "api/internal/manager/pause-logging"
req := newInternalRequest(ctx, reqURL, "POST")
return requestJSONUserMsg(req, "Logging Paused")
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, "Logging Paused"
}
// ResumeLogging resumes logging
func ResumeLogging(ctx context.Context) ResponseExtra {
func ResumeLogging(ctx context.Context) (int, string) {
reqURL := setting.LocalURL + "api/internal/manager/resume-logging"
req := newInternalRequest(ctx, reqURL, "POST")
return requestJSONUserMsg(req, "Logging Restarted")
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, "Logging Restarted"
}
// ReleaseReopenLogging releases and reopens logging files
func ReleaseReopenLogging(ctx context.Context) ResponseExtra {
func ReleaseReopenLogging(ctx context.Context) (int, string) {
reqURL := setting.LocalURL + "api/internal/manager/release-and-reopen-logging"
req := newInternalRequest(ctx, reqURL, "POST")
return requestJSONUserMsg(req, "Logging Restarted")
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, "Logging Restarted"
}
// SetLogSQL sets database logging
func SetLogSQL(ctx context.Context, on bool) ResponseExtra {
func SetLogSQL(ctx context.Context, on bool) (int, string) {
reqURL := setting.LocalURL + "api/internal/manager/set-log-sql?on=" + strconv.FormatBool(on)
req := newInternalRequest(ctx, reqURL, "POST")
return requestJSONUserMsg(req, "Log SQL setting set")
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, "Log SQL setting set"
}
// LoggerOptions represents the options for the add logger call
@ -82,32 +166,67 @@ type LoggerOptions struct {
}
// AddLogger adds a logger
func AddLogger(ctx context.Context, group, name, mode string, config map[string]interface{}) ResponseExtra {
func AddLogger(ctx context.Context, group, name, mode string, config map[string]interface{}) (int, string) {
reqURL := setting.LocalURL + "api/internal/manager/add-logger"
req := newInternalRequest(ctx, reqURL, "POST", LoggerOptions{
req := newInternalRequest(ctx, reqURL, "POST")
req = req.Header("Content-Type", "application/json")
jsonBytes, _ := json.Marshal(LoggerOptions{
Group: group,
Name: name,
Mode: mode,
Config: config,
})
return requestJSONUserMsg(req, "Added")
req.Body(jsonBytes)
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, "Added"
}
// RemoveLogger removes a logger
func RemoveLogger(ctx context.Context, group, name string) ResponseExtra {
func RemoveLogger(ctx context.Context, group, name string) (int, string) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/manager/remove-logger/%s/%s", url.PathEscape(group), url.PathEscape(name))
req := newInternalRequest(ctx, reqURL, "POST")
return requestJSONUserMsg(req, "Removed")
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
return http.StatusOK, "Removed"
}
// Processes return the current processes from this gitea instance
func Processes(ctx context.Context, out io.Writer, flat, noSystem, stacktraces, json bool, cancel string) ResponseExtra {
func Processes(ctx context.Context, out io.Writer, flat, noSystem, stacktraces, json bool, cancel string) (int, string) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/manager/processes?flat=%t&no-system=%t&stacktraces=%t&json=%t&cancel-pid=%s", flat, noSystem, stacktraces, json, url.QueryEscape(cancel))
req := newInternalRequest(ctx, reqURL, "GET")
callback := func(resp *http.Response, extra *ResponseExtra) {
_, extra.Error = io.Copy(out, resp.Body)
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
}
_, extra := requestJSONResp(req, &callback)
return extra
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return resp.StatusCode, decodeJSONError(resp).Err
}
_, err = io.Copy(out, resp.Body)
if err != nil {
return http.StatusInternalServerError, err.Error()
}
return http.StatusOK, ""
}

View File

@ -1,135 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package private
import (
"fmt"
"io"
"net/http"
"unicode"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/json"
)
// responseText is used to get the response as text, instead of parsing it as JSON.
type responseText struct {
Text string
}
// ResponseExtra contains extra information about the response, especially for error responses.
type ResponseExtra struct {
StatusCode int
UserMsg string
Error error
}
type responseCallback func(resp *http.Response, extra *ResponseExtra)
func (re *ResponseExtra) HasError() bool {
return re.Error != nil
}
type responseError struct {
statusCode int
errorString string
}
func (re responseError) Error() string {
if re.errorString == "" {
return fmt.Sprintf("internal API error response, status=%d", re.statusCode)
}
return fmt.Sprintf("internal API error response, status=%d, err=%s", re.statusCode, re.errorString)
}
// requestJSONUserMsg sends a request to the gitea server and then parses the response.
// If the status code is not 2xx, or any error occurs, the ResponseExtra.Error field is guaranteed to be non-nil,
// and the ResponseExtra.UserMsg field will be set to a message for the end user.
//
// * If the "res" is a struct pointer, the response will be parsed as JSON
// * If the "res" is responseText pointer, the response will be stored as text in it
// * If the "res" is responseCallback pointer, the callback function should set the ResponseExtra fields accordingly
func requestJSONResp[T any](req *httplib.Request, res *T) (ret *T, extra ResponseExtra) {
resp, err := req.Response()
if err != nil {
extra.UserMsg = "Internal Server Connection Error"
extra.Error = fmt.Errorf("unable to contact gitea %q: %w", req.GoString(), err)
return nil, extra
}
defer resp.Body.Close()
extra.StatusCode = resp.StatusCode
// if the status code is not 2xx, try to parse the error response
if resp.StatusCode/100 != 2 {
var respErr Response
if err := json.NewDecoder(resp.Body).Decode(&respErr); err != nil {
extra.UserMsg = "Internal Server Error Decoding Failed"
extra.Error = fmt.Errorf("unable to decode error response %q: %w", req.GoString(), err)
return nil, extra
}
extra.UserMsg = respErr.UserMsg
if extra.UserMsg == "" {
extra.UserMsg = "Internal Server Error (no message for end users)"
}
extra.Error = responseError{statusCode: resp.StatusCode, errorString: respErr.Err}
return res, extra
}
// now, the StatusCode must be 2xx
var v any = res
if respText, ok := v.(*responseText); ok {
// get the whole response as a text string
bs, err := io.ReadAll(resp.Body)
if err != nil {
extra.UserMsg = "Internal Server Response Reading Failed"
extra.Error = fmt.Errorf("unable to read response %q: %w", req.GoString(), err)
return nil, extra
}
respText.Text = string(bs)
return res, extra
} else if callback, ok := v.(*responseCallback); ok {
// pass the response to callback, and let the callback update the ResponseExtra
extra.StatusCode = resp.StatusCode
(*callback)(resp, &extra)
return nil, extra
} else if err := json.NewDecoder(resp.Body).Decode(res); err != nil {
// decode the response into the given struct
extra.UserMsg = "Internal Server Response Decoding Failed"
extra.Error = fmt.Errorf("unable to decode response %q: %w", req.GoString(), err)
return nil, extra
}
if respMsg, ok := v.(*Response); ok {
// if the "res" is Response structure, try to get the UserMsg from it and update the ResponseExtra
extra.UserMsg = respMsg.UserMsg
if respMsg.Err != "" {
// usually this shouldn't happen, because the StatusCode is 2xx, there should be no error.
// but we still handle the "err" response, in case some people return error messages by status code 200.
extra.Error = responseError{statusCode: resp.StatusCode, errorString: respMsg.Err}
}
}
return res, extra
}
// requestJSONUserMsg sends a request to the gitea server and then parses the response as private.Response
// If the request succeeds, the successMsg will be used as part of ResponseExtra.UserMsg.
func requestJSONUserMsg(req *httplib.Request, successMsg string) ResponseExtra {
resp, extra := requestJSONResp(req, &Response{})
if extra.HasError() {
return extra
}
if resp.UserMsg == "" {
extra.UserMsg = successMsg // if UserMsg is empty, then use successMsg as userMsg
} else if successMsg != "" {
// else, now UserMsg is not empty, if successMsg is not empty, then append successMsg to UserMsg
if unicode.IsPunct(rune(extra.UserMsg[len(extra.UserMsg)-1])) {
extra.UserMsg = extra.UserMsg + " " + successMsg
} else {
extra.UserMsg = extra.UserMsg + ". " + successMsg
}
}
return extra
}

View File

@ -6,8 +6,11 @@ package private
import (
"context"
"fmt"
"io"
"net/http"
"time"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
@ -21,16 +24,39 @@ type RestoreParams struct {
}
// RestoreRepo calls the internal RestoreRepo function
func RestoreRepo(ctx context.Context, repoDir, ownerName, repoName string, units []string, validation bool) ResponseExtra {
func RestoreRepo(ctx context.Context, repoDir, ownerName, repoName string, units []string, validation bool) (int, string) {
reqURL := setting.LocalURL + "api/internal/restore_repo"
req := newInternalRequest(ctx, reqURL, "POST", RestoreParams{
req := newInternalRequest(ctx, reqURL, "POST")
req.SetTimeout(3*time.Second, 0) // since the request will spend much time, don't timeout
req = req.Header("Content-Type", "application/json")
jsonBytes, _ := json.Marshal(RestoreParams{
RepoDir: repoDir,
OwnerName: ownerName,
RepoName: repoName,
Units: units,
Validation: validation,
})
req.SetTimeout(3*time.Second, 0) // since the request will spend much time, don't timeout
return requestJSONUserMsg(req, fmt.Sprintf("Restore repo %s/%s successfully", ownerName, repoName))
req.Body(jsonBytes)
resp, err := req.Response()
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v, could you confirm it's running?", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
ret := struct {
Err string `json:"err"`
}{}
body, err := io.ReadAll(resp.Body)
if err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Response body error: %v", err.Error())
}
if err := json.Unmarshal(body, &ret); err != nil {
return http.StatusInternalServerError, fmt.Sprintf("Response body Unmarshal error: %v", err.Error())
}
return http.StatusInternalServerError, ret.Err
}
return http.StatusOK, fmt.Sprintf("Restore repo %s/%s successfully", ownerName, repoName)
}

View File

@ -6,11 +6,13 @@ package private
import (
"context"
"fmt"
"net/http"
"net/url"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
@ -22,11 +24,20 @@ type KeyAndOwner struct {
// ServNoCommand returns information about the provided key
func ServNoCommand(ctx context.Context, keyID int64) (*asymkey_model.PublicKey, *user_model.User, error) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/none/%d", keyID)
req := newInternalRequest(ctx, reqURL, "GET")
keyAndOwner, extra := requestJSONResp(req, &KeyAndOwner{})
if extra.HasError() {
return nil, nil, extra.Error
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/none/%d",
keyID)
resp, err := newInternalRequest(ctx, reqURL, "GET").Response()
if err != nil {
return nil, nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, nil, fmt.Errorf("%s", decodeJSONError(resp).Err)
}
var keyAndOwner KeyAndOwner
if err := json.NewDecoder(resp.Body).Decode(&keyAndOwner); err != nil {
return nil, nil, err
}
return keyAndOwner.Key, keyAndOwner.Owner, nil
}
@ -45,19 +56,53 @@ type ServCommandResults struct {
RepoID int64
}
// ErrServCommand is an error returned from ServCommmand.
type ErrServCommand struct {
Results ServCommandResults
Err string
StatusCode int
}
func (err ErrServCommand) Error() string {
return err.Err
}
// IsErrServCommand checks if an error is a ErrServCommand.
func IsErrServCommand(err error) bool {
_, ok := err.(ErrServCommand)
return ok
}
// ServCommand preps for a serv call
func ServCommand(ctx context.Context, keyID int64, ownerName, repoName string, mode perm.AccessMode, verbs ...string) (*ServCommandResults, ResponseExtra) {
func ServCommand(ctx context.Context, keyID int64, ownerName, repoName string, mode perm.AccessMode, verbs ...string) (*ServCommandResults, error) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/command/%d/%s/%s?mode=%d",
keyID,
url.PathEscape(ownerName),
url.PathEscape(repoName),
mode,
)
mode)
for _, verb := range verbs {
if verb != "" {
reqURL += fmt.Sprintf("&verb=%s", url.QueryEscape(verb))
}
}
req := newInternalRequest(ctx, reqURL, "GET")
return requestJSONResp(req, &ServCommandResults{})
resp, err := newInternalRequest(ctx, reqURL, "GET").Response()
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var errServCommand ErrServCommand
if err := json.NewDecoder(resp.Body).Decode(&errServCommand); err != nil {
return nil, err
}
errServCommand.StatusCode = resp.StatusCode
return nil, errServCommand
}
var results ServCommandResults
if err := json.NewDecoder(resp.Body).Decode(&results); err != nil {
return nil, err
}
return &results, nil
}

View File

@ -139,9 +139,6 @@ func loadUIFrom(rootCfg ConfigProvider) {
UI.DefaultShowFullName = sec.Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
UI.SearchRepoDescription = sec.Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
UI.UseServiceWorker = sec.Key("USE_SERVICE_WORKER").MustBool(false)
// OnlyShowRelevantRepos=false is important for many private/enterprise instances,
// because many private repositories do not have "description/topic", users just want to search by their names.
UI.OnlyShowRelevantRepos = sec.Key("ONLY_SHOW_RELEVANT_REPOS").MustBool(false)
UI.ReactionsLookup = make(container.Set[string])

View File

@ -1250,7 +1250,6 @@ issues.new.no_assignees=Bez zpracovatelů
issues.new.no_reviewers=Žádní posuzovatelé
issues.new.add_reviewer_title=Požádat o posouzení
issues.choose.get_started=Začínáme
issues.choose.open_external_link=Otevřít
issues.choose.blank=Výchozí
issues.choose.blank_about=Vytvořit úkol z výchozí šablony.
issues.choose.ignore_invalid_templates=Neplatné šablony byly ignorovány

View File

@ -1202,7 +1202,6 @@ issues.new.no_assignees=Niemand zuständig
issues.new.no_reviewers=Keine Reviewer
issues.new.add_reviewer_title=Überprüfung anfordern
issues.choose.get_started=Los geht's
issues.choose.open_external_link=Öffnen
issues.choose.blank=Standard
issues.choose.blank_about=Erstelle einen Issue aus dem Standardtemplate.
issues.no_ref=Keine Branch/Tag angegeben

View File

@ -1259,7 +1259,6 @@ issues.new.no_assignees=Χωρίς Αποδέκτη
issues.new.no_reviewers=Δεν υπάρχουν εξεταστές
issues.new.add_reviewer_title=Αίτηση επανεξέτασης
issues.choose.get_started=Ας Αρχίσουμε
issues.choose.open_external_link=Άνοιγμα
issues.choose.blank=Προεπιλογή
issues.choose.blank_about=Δημιουργήστε ένα ζήτημα από το προεπιλεγμένο πρότυπο.
issues.choose.ignore_invalid_templates=Μη έγκυρα πρότυπα έχουν αγνοηθεί

View File

@ -1224,7 +1224,6 @@ issues.new.no_assignees=No asignados
issues.new.no_reviewers=No hay revisores
issues.new.add_reviewer_title=Solicitar revisión
issues.choose.get_started=Comenzar
issues.choose.open_external_link=Abrir
issues.choose.blank=Predeterminado
issues.choose.blank_about=Crear una incidencia a partir de la plantilla predeterminada.
issues.choose.ignore_invalid_templates=Las plantillas no válidas han sido ignoradas

View File

@ -1117,7 +1117,6 @@ issues.new.no_assignees=بدون تخصیص
issues.new.no_reviewers=بدون بازبین گر
issues.new.add_reviewer_title=درخواست بازبینی
issues.choose.get_started=آغاز کردن
issues.choose.open_external_link=باز‌کردن
issues.choose.blank=پیشگزیده
issues.choose.blank_about=ایجاد یک مشکل از ساختار پیش‌فرض
issues.no_ref=بدون شاخه/برچسب مشخص

View File

@ -867,7 +867,6 @@ issues.new.assignees=Käsittelijä
issues.new.add_assignees_title=Osoita käyttäjille
issues.new.clear_assignees=Tyhjennä käsittelijä
issues.new.no_assignees=Ei käsittelijää
issues.choose.open_external_link=Avaa
issues.choose.blank=Oletus
issues.no_ref=Haaraa/tagia ei määritelty
issues.create=Ilmoita ongelma

View File

@ -971,7 +971,6 @@ issues.new.no_assignees=Pas d'assignataires
issues.new.no_reviewers=Aucune évaluation
issues.new.add_reviewer_title=Demander une revue
issues.choose.get_started=Démarrons
issues.choose.open_external_link=Ouvrir
issues.choose.blank=Par défaut
issues.choose.blank_about=Créer un ticket à partir du modèle par défaut.
issues.no_ref=Aucune branche/étiquette spécifiées

View File

@ -774,7 +774,6 @@ issues.new.open_projects=Opin Verkefni
issues.new.closed_projects=Lokuð Verkefni
issues.new.milestone=Tímamót
issues.choose.get_started=Hefjast Handa
issues.choose.open_external_link=Opna
issues.choose.blank=Sjálfgefið
issues.no_ref=Engin Grein eða Merki Tilgreint
issues.create=Skapa Vandamálsumræðu

View File

@ -1211,7 +1211,6 @@ issues.new.no_assignees=Nessuna assegnatario
issues.new.no_reviewers=Nessun revisore
issues.new.add_reviewer_title=Richiedi revisione
issues.choose.get_started=Inizia
issues.choose.open_external_link=Apri
issues.choose.blank=Default
issues.choose.blank_about=Crea un problema dal modello predefinito.
issues.no_ref=Nessun Branch/Tag specificato

View File

@ -1271,7 +1271,6 @@ issues.new.no_assignees=担当者なし
issues.new.no_reviewers=レビューアなし
issues.new.add_reviewer_title=レビュー依頼
issues.choose.get_started=始める
issues.choose.open_external_link=オープン
issues.choose.blank=デフォルト
issues.choose.blank_about=デフォルトのテンプレートからイシューを作成。
issues.choose.ignore_invalid_templates=無効なテンプレートが無視されました

View File

@ -1259,7 +1259,6 @@ issues.new.no_assignees=Nav atbildīgo
issues.new.no_reviewers=Nav recenzentu
issues.new.add_reviewer_title=Pieprasīt recenziju
issues.choose.get_started=Sākt darbu
issues.choose.open_external_link=Aktīvie
issues.choose.blank=Noklusējuma
issues.choose.blank_about=Izveidot problēmu ar noklusējuma sagatavi.
issues.choose.ignore_invalid_templates=Kļūdainās sagataves tika izlaistas

View File

@ -1211,7 +1211,6 @@ issues.new.no_assignees=Niet toegewezen
issues.new.no_reviewers=Geen beoordelaars
issues.new.add_reviewer_title=Beoordeling aanvragen
issues.choose.get_started=Ga aan de slag
issues.choose.open_external_link=Open
issues.choose.blank=Standaard
issues.choose.blank_about=Maak een issue aan via een standaard sjabloon.
issues.no_ref=Geen Branch/Tag gespecificeerd

View File

@ -1120,7 +1120,6 @@ issues.new.no_assignees=Brak przypisanych
issues.new.no_reviewers=Brak recenzentów
issues.new.add_reviewer_title=Poproś o recenzję
issues.choose.get_started=Rozpocznij
issues.choose.open_external_link=Otwórz
issues.choose.blank=Domyślny
issues.choose.blank_about=Utwórz problem z domyślnego szablonu.
issues.no_ref=Nie określono gałęzi/etykiety

View File

@ -1259,7 +1259,6 @@ issues.new.no_assignees=Sem responsável
issues.new.no_reviewers=Sem revisor
issues.new.add_reviewer_title=Solicitar revisão
issues.choose.get_started=Primeiros passos
issues.choose.open_external_link=Abrir
issues.choose.blank=Padrão
issues.choose.blank_about=Criar uma issue a partir do modelo padrão.
issues.choose.ignore_invalid_templates=Modelos inválidos foram ignorados

View File

@ -1068,7 +1068,6 @@ release=Lançamento
releases=Lançamentos
tag=Etiqueta
released_this=lançou isto
tagged_this=etiquetou isto
file.title=%s em %s
file_raw=Em bruto
file_history=Histórico
@ -1272,12 +1271,10 @@ issues.new.no_assignees=Sem encarregados
issues.new.no_reviewers=Sem revisores
issues.new.add_reviewer_title=Solicitar revisão
issues.choose.get_started=Começar
issues.choose.open_external_link=Abrir
issues.choose.blank=Padrão
issues.choose.blank_about=Cria uma questão a partir do modelo padrão.
issues.choose.ignore_invalid_templates=Modelos inválidos foram ignorados
issues.choose.invalid_templates=Foram encontrados %v modelos inválidos
issues.choose.invalid_config=A configuração das questões contém erros:
issues.no_ref=Sem ramo ou etiqueta especificados
issues.create=Criar questão
issues.new_label=Novo rótulo
@ -1491,9 +1488,6 @@ issues.due_date_invalid=A data de vencimento é inválida ou está fora do inter
issues.dependency.title=Dependências
issues.dependency.issue_no_dependencies=Não estão definidas dependências.
issues.dependency.pr_no_dependencies=Não estão definidas dependências.
issues.dependency.no_permission_1=Você não tem permissão para ler %d dependência
issues.dependency.no_permission_n=Você não tem permissão para ler %d dependências
issues.dependency.no_permission.can_remove=Você não tem permissão para ler esta dependência, mas pode removê-la
issues.dependency.add=Adicionar dependência…
issues.dependency.cancel=Cancelar
issues.dependency.remove=Remover

View File

@ -1177,7 +1177,6 @@ issues.new.no_assignees=Нет назначенных лиц
issues.new.no_reviewers=Нет рецензентов
issues.new.add_reviewer_title=Запросить отзыв
issues.choose.get_started=Начать
issues.choose.open_external_link=Открыть
issues.choose.blank=По умолчанию
issues.choose.blank_about=Создать запрос из шаблона по умолчанию.
issues.no_ref=Не указана ветка или тэг

View File

@ -1076,7 +1076,6 @@ issues.new.no_assignees=කිසිදු සහස්ර
issues.new.no_reviewers=විචාරකයින් නැත
issues.new.add_reviewer_title=ඉල්ලීම සමාලෝචනය
issues.choose.get_started=ආරම්භ කරන්න
issues.choose.open_external_link=විවෘත
issues.choose.blank=පෙරනිමි
issues.choose.blank_about=පෙරනිමි සැකිල්ලෙන් ප්රශ්නයක් සාදන්න.
issues.no_ref=කිසිදු ශාඛාව/ටැග නිශ්චිතව දක්වා

View File

@ -1022,7 +1022,6 @@ issues.new.projects=Projekty
issues.new.milestone=Míľnik
issues.new.no_reviewers=Žiadni revidenti
issues.new.add_reviewer_title=Požiadať o revíziu
issues.choose.open_external_link=Otvoriť
issues.choose.blank_about=Vytvoriť úkol z predvolenej šablóny.
issues.create=Vytvoriť úkol
issues.filter_label=Štítok

View File

@ -918,7 +918,6 @@ issues.new.no_assignees=Ingen tilldelad
issues.new.no_reviewers=Inga granskare
issues.new.add_reviewer_title=Begär granskning
issues.choose.get_started=Kom igång
issues.choose.open_external_link=Öppna
issues.choose.blank=Standard
issues.choose.blank_about=Skapa ett ärende från standardmall.
issues.no_ref=Ingen Branch/Tag specificerad

View File

@ -1232,7 +1232,6 @@ issues.new.no_assignees=Atanan Kişi Yok
issues.new.no_reviewers=Değerlendirici yok
issues.new.add_reviewer_title=İnceleme iste
issues.choose.get_started=Başla
issues.choose.open_external_link=
issues.choose.blank=Varsayılan
issues.choose.blank_about=Varsayılan şablondan bir konu oluşturun.
issues.choose.ignore_invalid_templates=Geçersiz şablonlar göz ardı edildi

View File

@ -1126,7 +1126,6 @@ issues.new.no_assignees=Немає виконавця
issues.new.no_reviewers=Немає рецензентів
issues.new.add_reviewer_title=Попросити рецензію
issues.choose.get_started=Початок роботи
issues.choose.open_external_link=Відкрити
issues.choose.blank=Типово
issues.choose.blank_about=Створити задачу із шаблону за замовчуванням.
issues.no_ref=Не вказана гілка або тег

View File

@ -1271,7 +1271,6 @@ issues.new.no_assignees=未指派成员
issues.new.no_reviewers=无审核者
issues.new.add_reviewer_title=请求审核
issues.choose.get_started=开始
issues.choose.open_external_link=开启
issues.choose.blank=默认模板
issues.choose.blank_about=从默认模板创建一个工单。
issues.choose.ignore_invalid_templates=已忽略无效模板

View File

@ -249,7 +249,6 @@ no_reply_address=隱藏電子信箱域名
no_reply_address_helper=作為隱藏電子信箱使用者的域名。例如如果隱藏的電子信箱域名設定為「noreply.example.org」帳號「joe」將以「joe@noreply.example.org」的身分登錄到 Git 中。
password_algorithm=密碼雜湊演算法
invalid_password_algorithm=無效的密碼雜湊演算法
password_algorithm_helper=設定密碼雜湊演算法。演算法有不同的需求與強度。argon2 演算法雖然較安全但會使用大量記憶體,可能不適用於小型系統。
enable_update_checker=啟用更新檢查器
enable_update_checker_helper=定期連線到 gitea.io 檢查更新。
@ -521,14 +520,8 @@ invalid_ssh_key=無法驗證您的 SSH 密鑰:%s
invalid_gpg_key=無法驗證您的 GPG 密鑰:%s
invalid_ssh_principal=無效的主體: %s
must_use_public_key=您提供的金鑰是私有金鑰,請勿上傳您的私有金鑰到任何地方,請使用您的公鑰。
unable_verify_ssh_key=無法驗證 SSH 金鑰,請再次檢查以避免錯誤。
auth_failed=授權認證失敗:%v
still_own_repo=您的帳戶擁有一個以上的儲存庫,請先刪除或轉移它們。
still_has_org=您的帳戶是一個或多個組織的成員,請先離開它們。
still_own_packages=您的帳戶擁有一個以上的套件,請先刪除它們。
org_still_own_repo=此組織仍然擁有一個以上的儲存庫,請先刪除或轉移它們。
org_still_own_packages=此組織仍然擁有一個以上的套件,請先刪除它們。
target_branch_not_exist=目標分支不存在
@ -993,7 +986,6 @@ migrate.github_token_desc=由於 GitHub API 的速率限制,您可在此輸入
migrate.clone_local_path=或者是本地端伺服器路徑
migrate.permission_denied=您並沒有導入本地儲存庫的權限。
migrate.permission_denied_blocked=您無法從未允許的主機匯入,請聯絡管理員檢查以下設定值 ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS
migrate.invalid_local_path=無效的本地路徑,該路徑不存在或不是一個目錄。
migrate.invalid_lfs_endpoint=該 LFS 端點無效。
migrate.failed=遷移失敗:%v
migrate.migrate_items_options=遷移其他項目需要 Access Token。
@ -1175,7 +1167,6 @@ commits.commits=次程式碼提交
commits.no_commits=沒有共同的提交。「%s」和「%s」的歷史完全不同。
commits.nothing_to_compare=這些分支是相同的。
commits.search=搜尋提交歷史...
commits.search.tooltip=你可以用「author:」、「committer:」、「after:」、「before:」等作為關鍵字的前綴,例如: 「revert author:Alice before:2019-01-13」。
commits.find=搜尋
commits.search_all=所有分支
commits.author=作者
@ -1271,7 +1262,6 @@ issues.new.no_assignees=沒有負責人
issues.new.no_reviewers=沒有審核者
issues.new.add_reviewer_title=請求審核
issues.choose.get_started=開始
issues.choose.open_external_link=開啟
issues.choose.blank=預設
issues.choose.blank_about=從預設範本建立問題。
issues.choose.ignore_invalid_templates=已忽略無效的範本
@ -2476,7 +2466,6 @@ teams.remove_all_repos_title=移除所有團隊儲存庫
teams.remove_all_repos_desc=這將從團隊中移除所有儲存庫。
teams.add_all_repos_title=增加所有儲存庫
teams.add_all_repos_desc=這將把組織的所有儲存庫增加到團隊。
teams.add_nonexistent_repo=您嘗試新增的儲存庫不存在,請先建立它。
teams.add_duplicate_users=使用者已經是團隊成員了。
teams.repos.none=這個團隊沒有可以存取的儲存庫。
teams.members.none=這個團隊沒有任何成員。
@ -2506,7 +2495,6 @@ first_page=首頁
last_page=末頁
total=總計:%d
dashboard.new_version_hint=現已推出 Gitea %s您正在執行 %s。詳情請參閱<a target="_blank" rel="noreferrer" href="https://blog.gitea.io">部落格</a>的說明。
dashboard.statistic=摘要
dashboard.operations=維護作業
dashboard.system_status=系統狀態
@ -2626,7 +2614,6 @@ users.still_own_repo=這個使用者還擁有一個或更多的儲存庫。請
users.still_has_org=此使用者是組織的成員。請先將他從組織中移除。
users.purge=清除使用者
users.purge_help=強制刪除使用者和他擁有的所有儲存庫、組織、套件,所有留言也會被刪除。
users.still_own_packages=此使用者仍然擁有一個以上的套件,請先刪除這些套件。
users.deletion_success=使用者帳戶已被刪除。
users.reset_2fa=重設兩步驟驗證
users.list_status_filter.menu_text=篩選

View File

@ -149,7 +149,10 @@ func (s *Service) UpdateTask(
return nil, status.Errorf(codes.Internal, "load job: %v", err)
}
actions_service.CreateCommitStatus(ctx, task.Job)
if err := actions_service.CreateCommitStatus(ctx, task.Job); err != nil {
log.Error("Update commit status for job %v failed: %v", task.Job.ID, err)
// go on
}
if req.Msg.State.Result != runnerv1.Result_RESULT_UNSPECIFIED {
if err := actions_service.EmitJobsIfReady(task.Job.RunID); err != nil {

View File

@ -13,7 +13,6 @@ import (
"code.gitea.io/gitea/modules/log"
secret_module "code.gitea.io/gitea/modules/secret"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/actions"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
"google.golang.org/protobuf/types/known/structpb"
@ -28,8 +27,6 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
return nil, false, nil
}
actions.CreateCommitStatus(ctx, t.Job)
task := &runnerv1.Task{
Id: t.ID,
WorkflowPayload: t.Job.WorkflowPayload,

View File

@ -1,6 +1,7 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@ -13,6 +14,19 @@ import (
"code.gitea.io/gitea/modules/private"
)
// ________ _____ .__ __
// \______ \ _____/ ____\____ __ __| |_/ |_
// | | \_/ __ \ __\\__ \ | | \ |\ __\
// | ` \ ___/| | / __ \| | / |_| |
// /_______ /\___ >__| (____ /____/|____/__|
// \/ \/ \/
// __________ .__
// \______ \____________ ____ ____ | |__
// | | _/\_ __ \__ \ / \_/ ___\| | \
// | | \ | | \// __ \| | \ \___| Y \
// |______ / |__| (____ /___| /\___ >___| /
// \/ \/ \/ \/ \/
// SetDefaultBranch updates the default branch
func SetDefaultBranch(ctx *gitea_context.PrivateContext) {
ownerName := ctx.Params(":owner")

View File

@ -1,6 +1,7 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (

View File

@ -1,6 +1,7 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@ -68,8 +69,8 @@ func (ctx *preReceiveContext) AssertCanWriteCode() bool {
if ctx.Written() {
return false
}
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "User permission denied for writing.",
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"err": "User permission denied for writing.",
})
return false
}
@ -94,8 +95,8 @@ func (ctx *preReceiveContext) AssertCreatePullRequest() bool {
if ctx.Written() {
return false
}
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "User permission denied for creating pull-request.",
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"err": "User permission denied for creating pull-request.",
})
return false
}
@ -150,7 +151,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if branchName == repo.DefaultBranch && newCommitID == git.EmptySHA {
log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName),
Err: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName),
})
return
}
@ -178,7 +179,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if newCommitID == git.EmptySHA {
log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is protected from deletion", branchName),
Err: fmt.Sprintf("branch %s is protected from deletion", branchName),
})
return
}
@ -195,7 +196,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
} else if len(output) > 0 {
log.Warn("Forbidden: Branch: %s in %-v is protected from force push", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is protected from force push", branchName),
Err: fmt.Sprintf("branch %s is protected from force push", branchName),
})
return
@ -216,7 +217,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
unverifiedCommit := err.(*errUnverifiedCommit).sha
log.Warn("Forbidden: Branch: %s in %-v is protected from unverified commit %s", branchName, repo, unverifiedCommit)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is protected from unverified commit %s", branchName, unverifiedCommit),
Err: fmt.Sprintf("branch %s is protected from unverified commit %s", branchName, unverifiedCommit),
})
return
}
@ -271,7 +272,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if changedProtectedfiles {
log.Warn("Forbidden: Branch: %s in %-v is protected from changing file %s", branchName, repo, protectedFilePath)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
Err: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
})
return
}
@ -296,7 +297,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
// Or we're simply not able to push to this protected branch
log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v", ctx.opts.UserID, branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
Err: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
})
return
}
@ -332,7 +333,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if !allowedMerge {
log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v and is not allowed to merge pr #%d", ctx.opts.UserID, branchName, repo, pr.Index)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
Err: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
})
return
}
@ -346,7 +347,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if changedProtectedfiles {
log.Warn("Forbidden: Branch: %s in %-v is protected from changing file %s", branchName, repo, protectedFilePath)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
Err: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
})
return
}
@ -356,7 +357,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if models.IsErrDisallowedToMerge(err) {
log.Warn("Forbidden: User %d is not allowed push to protected branch %s in %-v and pr #%d is not ready to be merged: %s", ctx.opts.UserID, branchName, repo, pr.Index, err.Error())
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s and pr #%d is not ready to be merged: %s", branchName, ctx.opts.PullRequestID, err.Error()),
Err: fmt.Sprintf("Not allowed to push to protected branch %s and pr #%d is not ready to be merged: %s", branchName, ctx.opts.PullRequestID, err.Error()),
})
return
}
@ -399,7 +400,7 @@ func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID, refFullName
if !isAllowed {
log.Warn("Forbidden: Tag %s in %-v is protected", tagName, ctx.Repo.Repository)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("Tag %s is protected", tagName),
Err: fmt.Sprintf("Tag %s is protected", tagName),
})
return
}
@ -411,15 +412,15 @@ func preReceivePullRequest(ctx *preReceiveContext, oldCommitID, newCommitID, ref
}
if ctx.Repo.Repository.IsEmpty {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Can't create pull request for an empty repository.",
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"err": "Can't create pull request for an empty repository.",
})
return
}
if ctx.opts.IsWiki {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Pull requests are not supported on the wiki.",
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"err": "Pull requests are not supported on the wiki.",
})
return
}
@ -442,7 +443,7 @@ func preReceivePullRequest(ctx *preReceiveContext, oldCommitID, newCommitID, ref
if !baseBranchExist {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("Unexpected ref: %s", refFullName),
Err: fmt.Sprintf("Unexpected ref: %s", refFullName),
})
return
}

View File

@ -1,6 +1,7 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@ -29,8 +30,8 @@ func HookProcReceive(ctx *gitea_context.PrivateContext) {
ctx.Error(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err.Error())
} else {
log.Error(err.Error())
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(),
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"Err": err.Error(),
})
}

View File

@ -1,6 +1,7 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@ -15,6 +16,19 @@ import (
"code.gitea.io/gitea/modules/log"
)
// _________ .__ __
// \_ ___ \ ____ _____ _____ |__|/ |_
// / \ \/ / _ \ / \ / \| \ __\
// \ \___( <_> ) Y Y \ Y Y \ || |
// \______ /\____/|__|_| /__|_| /__||__|
// \/ \/ \/
// ____ ____ .__ _____.__ __ .__
// \ \ / /___________|__|/ ____\__| ____ _____ _/ |_|__| ____ ____
// \ Y // __ \_ __ \ \ __\| |/ ___\\__ \\ __\ |/ _ \ / \
// \ /\ ___/| | \/ || | | \ \___ / __ \| | | ( <_> ) | \
// \___/ \___ >__| |__||__| |__|\___ >____ /__| |__|\____/|___| /
// \/ \/ \/ \/
//
// This file contains commit verification functions for refs passed across in hooks
func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []string) error {

View File

@ -1,7 +1,7 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Package private contains all internal routes. The package name "internal" isn't usable because Golang reserves it for disabling cross-package usage.
// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (

View File

@ -1,6 +1,7 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@ -12,10 +13,23 @@ import (
gitea_context "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
)
// This file contains common functions relating to setting the Repository for the internal routes
// __________
// \______ \ ____ ______ ____
// | _// __ \\____ \ / _ \
// | | \ ___/| |_> > <_> )
// |____|_ /\___ > __/ \____/
// \/ \/|__|
// _____ .__ __
// / _ \ ______ _____|__| ____ ____ _____ ____ _____/ |_
// / /_\ \ / ___// ___/ |/ ___\ / \ / \_/ __ \ / \ __\
// / | \\___ \ \___ \| / /_/ > | \ Y Y \ ___/| | \ |
// \____|__ /____ >____ >__\___ /|___| /__|_| /\___ >___| /__|
// \/ \/ \/ /_____/ \/ \/ \/ \/
// This file contains common functions relating to setting the Repository for the
// internal routes
// RepoAssignment assigns the repository and gitrepository to the private context
func RepoAssignment(ctx *gitea_context.PrivateContext) context.CancelFunc {
@ -31,8 +45,8 @@ func RepoAssignment(ctx *gitea_context.PrivateContext) context.CancelFunc {
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
if err != nil {
log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err),
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"Err": fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err),
})
return nil
}
@ -57,8 +71,8 @@ func loadRepository(ctx *gitea_context.PrivateContext, ownerName, repoName strin
repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ownerName, repoName)
if err != nil {
log.Error("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err),
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"Err": fmt.Sprintf("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err),
})
return nil
}

View File

@ -1,6 +1,7 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (

View File

@ -31,14 +31,14 @@ func FlushQueues(ctx *context.PrivateContext) {
}
}()
ctx.JSON(http.StatusAccepted, private.Response{
UserMsg: "Flushing",
Err: "Flushing",
})
return
}
err := queue.GetManager().FlushAll(ctx, opts.Timeout)
if err != nil {
ctx.JSON(http.StatusRequestTimeout, private.Response{
UserMsg: fmt.Sprintf("%v", err),
Err: fmt.Sprintf("%v", err),
})
}
ctx.PlainText(http.StatusOK, "success")

View File

@ -16,7 +16,7 @@ import (
// Restart is not implemented for Windows based servers as they can't fork
func Restart(ctx *context.PrivateContext) {
ctx.JSON(http.StatusNotImplemented, private.Response{
UserMsg: "windows servers cannot be gracefully restarted - shutdown and restart manually",
Err: "windows servers cannot be gracefully restarted - shutdown and restart manually",
})
}

View File

@ -1,6 +1,7 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@ -28,7 +29,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
keyID := ctx.ParamsInt64(":keyid")
if keyID <= 0 {
ctx.JSON(http.StatusBadRequest, private.Response{
UserMsg: fmt.Sprintf("Bad key id: %d", keyID),
Err: fmt.Sprintf("Bad key id: %d", keyID),
})
}
results := private.KeyAndOwner{}
@ -37,7 +38,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
if err != nil {
if asymkey_model.IsErrKeyNotExist(err) {
ctx.JSON(http.StatusUnauthorized, private.Response{
UserMsg: fmt.Sprintf("Cannot find key: %d", keyID),
Err: fmt.Sprintf("Cannot find key: %d", keyID),
})
return
}
@ -54,7 +55,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
if err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.JSON(http.StatusUnauthorized, private.Response{
UserMsg: fmt.Sprintf("Cannot find owner with id: %d for key: %d", key.OwnerID, keyID),
Err: fmt.Sprintf("Cannot find owner with id: %d for key: %d", key.OwnerID, keyID),
})
return
}
@ -66,7 +67,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
}
if !user.IsActive || user.ProhibitLogin {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Your account is disabled.",
Err: "Your account is disabled.",
})
return
}
@ -112,20 +113,23 @@ func ServCommand(ctx *context.PrivateContext) {
if user_model.IsErrUserNotExist(err) {
// User is fetching/cloning a non-existent repository
log.Warn("Failed authentication attempt (cannot find repository: %s/%s) from %s", results.OwnerName, results.RepoName, ctx.RemoteAddr())
ctx.JSON(http.StatusNotFound, private.Response{
UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
ctx.JSON(http.StatusNotFound, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
})
return
}
log.Error("Unable to get repository owner: %s/%s Error: %v", results.OwnerName, results.RepoName, err)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("Unable to get repository owner: %s/%s %v", results.OwnerName, results.RepoName, err),
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Unable to get repository owner: %s/%s %v", results.OwnerName, results.RepoName, err),
})
return
}
if !owner.IsOrganization() && !owner.IsActive {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Repository cannot be accessed, you could retry it later",
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
Results: results,
Err: "Repository cannot be accessed, you could retry it later",
})
return
}
@ -140,16 +144,18 @@ func ServCommand(ctx *context.PrivateContext) {
if verb == "git-upload-pack" {
// User is fetching/cloning a non-existent repository
log.Warn("Failed authentication attempt (cannot find repository: %s/%s) from %s", results.OwnerName, results.RepoName, ctx.RemoteAddr())
ctx.JSON(http.StatusNotFound, private.Response{
UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
ctx.JSON(http.StatusNotFound, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
})
return
}
}
} else {
log.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get repository: %s/%s %v", results.OwnerName, results.RepoName, err),
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Unable to get repository: %s/%s %v", results.OwnerName, results.RepoName, err),
})
return
}
@ -161,23 +167,26 @@ func ServCommand(ctx *context.PrivateContext) {
results.RepoID = repo.ID
if repo.IsBeingCreated() {
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: "Repository is being created, you could retry after it finished",
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: "Repository is being created, you could retry after it finished",
})
return
}
if repo.IsBroken() {
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: "Repository is in a broken state",
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 > perm.AccessModeRead && repo.IsMirror {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("Mirror Repository %s/%s is read-only", results.OwnerName, results.RepoName),
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Mirror Repository %s/%s is read-only", results.OwnerName, results.RepoName),
})
return
}
@ -187,14 +196,16 @@ func ServCommand(ctx *context.PrivateContext) {
key, err := asymkey_model.GetPublicKeyByID(keyID)
if err != nil {
if asymkey_model.IsErrKeyNotExist(err) {
ctx.JSON(http.StatusNotFound, private.Response{
UserMsg: fmt.Sprintf("Cannot find key: %d", keyID),
ctx.JSON(http.StatusNotFound, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Cannot find key: %d", keyID),
})
return
}
log.Error("Unable to get public key: %d Error: %v", keyID, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get key: %d Error: %v", keyID, err),
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Unable to get key: %d Error: %v", keyID, err),
})
return
}
@ -204,8 +215,9 @@ func ServCommand(ctx *context.PrivateContext) {
// If repo doesn't exist, deploy key doesn't make sense
if !repoExist && key.Type == asymkey_model.KeyTypeDeploy {
ctx.JSON(http.StatusNotFound, private.Response{
UserMsg: fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName),
ctx.JSON(http.StatusNotFound, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName),
})
return
}
@ -220,14 +232,16 @@ func ServCommand(ctx *context.PrivateContext) {
deployKey, err = asymkey_model.GetDeployKeyByRepo(ctx, key.ID, repo.ID)
if err != nil {
if asymkey_model.IsErrDeployKeyNotExist(err) {
ctx.JSON(http.StatusNotFound, private.Response{
UserMsg: fmt.Sprintf("Public (Deploy) Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName),
ctx.JSON(http.StatusNotFound, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Public (Deploy) Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName),
})
return
}
log.Error("Unable to get deploy for public (deploy) key: %d in %-v Error: %v", key.ID, repo, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get Deploy Key for Public Key: %d:%s in %s/%s.", key.ID, key.Name, results.OwnerName, results.RepoName),
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Unable to get Deploy Key for Public Key: %d:%s in %s/%s.", key.ID, key.Name, results.OwnerName, results.RepoName),
})
return
}
@ -248,21 +262,23 @@ func ServCommand(ctx *context.PrivateContext) {
user, err = user_model.GetUserByID(ctx, key.OwnerID)
if err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.JSON(http.StatusUnauthorized, private.Response{
UserMsg: fmt.Sprintf("Public Key: %d:%s owner %d does not exist.", key.ID, key.Name, key.OwnerID),
ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Public Key: %d:%s owner %d does not exist.", key.ID, key.Name, key.OwnerID),
})
return
}
log.Error("Unable to get owner: %d for public key: %d:%s Error: %v", key.OwnerID, key.ID, key.Name, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get Owner: %d for Deploy Key: %d:%s in %s/%s.", key.OwnerID, key.ID, key.Name, ownerName, repoName),
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Unable to get Owner: %d for Deploy Key: %d:%s in %s/%s.", key.OwnerID, key.ID, key.Name, ownerName, repoName),
})
return
}
if !user.IsActive || user.ProhibitLogin {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Your account is disabled.",
Err: "Your account is disabled.",
})
return
}
@ -275,8 +291,9 @@ func ServCommand(ctx *context.PrivateContext) {
// Don't allow pushing if the repo is archived
if repoExist && mode > perm.AccessModeRead && repo.IsArchived {
ctx.JSON(http.StatusUnauthorized, private.Response{
UserMsg: fmt.Sprintf("Repo: %s/%s is archived.", results.OwnerName, results.RepoName),
ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Repo: %s/%s is archived.", results.OwnerName, results.RepoName),
})
return
}
@ -290,8 +307,9 @@ func ServCommand(ctx *context.PrivateContext) {
setting.Service.RequireSignInView) {
if key.Type == asymkey_model.KeyTypeDeploy {
if deployKey.Mode < mode {
ctx.JSON(http.StatusUnauthorized, private.Response{
UserMsg: fmt.Sprintf("Deploy Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName),
ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Deploy Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName),
})
return
}
@ -304,8 +322,9 @@ func ServCommand(ctx *context.PrivateContext) {
perm, err := access_model.GetUserRepoPermission(ctx, repo, user)
if err != nil {
log.Error("Unable to get permissions for %-v with key %d in %-v Error: %v", user, key.ID, repo, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get permissions for user %d:%s with key %d in %s/%s Error: %v", user.ID, user.Name, key.ID, results.OwnerName, results.RepoName, err),
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Unable to get permissions for user %d:%s with key %d in %s/%s Error: %v", user.ID, user.Name, key.ID, results.OwnerName, results.RepoName, err),
})
return
}
@ -314,8 +333,9 @@ func ServCommand(ctx *context.PrivateContext) {
if userMode < mode {
log.Warn("Failed authentication attempt for %s with key %s (not authorized to %s %s/%s) from %s", user.Name, key.Name, modeString, ownerName, repoName, ctx.RemoteAddr())
ctx.JSON(http.StatusUnauthorized, private.Response{
UserMsg: fmt.Sprintf("User: %d:%s with Key: %d:%s is not authorized to %s %s/%s.", user.ID, user.Name, key.ID, key.Name, modeString, ownerName, repoName),
ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("User: %d:%s with Key: %d:%s is not authorized to %s %s/%s.", user.ID, user.Name, key.ID, key.Name, modeString, ownerName, repoName),
})
return
}
@ -326,21 +346,24 @@ func ServCommand(ctx *context.PrivateContext) {
if !repoExist {
owner, err := user_model.GetUserByName(ctx, ownerName)
if err != nil {
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get owner: %s %v", results.OwnerName, err),
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Unable to get owner: %s %v", results.OwnerName, err),
})
return
}
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Push to create is not enabled for organizations.",
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
Results: results,
Err: "Push to create is not enabled for organizations.",
})
return
}
if !owner.IsOrganization() && !setting.Repository.EnablePushCreateUser {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "Push to create is not enabled for users.",
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
Results: results,
Err: "Push to create is not enabled for users.",
})
return
}
@ -348,8 +371,9 @@ func ServCommand(ctx *context.PrivateContext) {
repo, err = repo_service.PushCreateRepo(ctx, user, owner, results.RepoName)
if err != nil {
log.Error("pushCreateRepo: %v", err)
ctx.JSON(http.StatusNotFound, private.Response{
UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
ctx.JSON(http.StatusNotFound, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
})
return
}
@ -360,14 +384,16 @@ func ServCommand(ctx *context.PrivateContext) {
// Ensure the wiki is enabled before we allow access to it
if _, err := repo.GetUnit(ctx, unit.TypeWiki); err != nil {
if repo_model.IsErrUnitTypeNotExist(err) {
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: "repository wiki is disabled",
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
Results: results,
Err: "repository wiki is disabled",
})
return
}
log.Error("Failed to get the wiki unit in %-v Error: %v", repo, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Failed to get the wiki unit in %s/%s Error: %v", ownerName, repoName, err),
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Failed to get the wiki unit in %s/%s Error: %v", ownerName, repoName, err),
})
return
}
@ -375,8 +401,9 @@ func ServCommand(ctx *context.PrivateContext) {
// Finally if we're trying to touch the wiki we should init it
if err = wiki_service.InitWiki(ctx, repo); err != nil {
log.Error("Failed to initialize the wiki in %-v Error: %v", repo, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Failed to initialize the wiki in %s/%s Error: %v", ownerName, repoName, err),
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
Results: results,
Err: fmt.Sprintf("Failed to initialize the wiki in %s/%s Error: %v", ownerName, repoName, err),
})
return
}

View File

@ -4,7 +4,6 @@
package explore
import (
"fmt"
"net/http"
"code.gitea.io/gitea/models/db"
@ -19,7 +18,7 @@ import (
const (
// tplExploreRepos explore repositories page template
tplExploreRepos base.TplName = "explore/repos"
relevantReposOnlyParam string = "only_show_relevant"
relevantReposOnlyParam string = "no_filter"
)
// RepoSearchOptions when calling search repositories
@ -138,7 +137,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "topic", "TopicOnly")
pager.AddParam(ctx, "language", "Language")
pager.AddParamString(relevantReposOnlyParam, fmt.Sprint(opts.OnlyShowRelevant))
pager.AddParamString(relevantReposOnlyParam, ctx.FormString(relevantReposOnlyParam))
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, opts.TplName)
@ -157,18 +156,11 @@ func Repos(ctx *context.Context) {
ownerID = ctx.Doer.ID
}
onlyShowRelevant := setting.UI.OnlyShowRelevantRepos
_ = ctx.Req.ParseForm() // parse the form first, to prepare the ctx.Req.Form field
if len(ctx.Req.Form[relevantReposOnlyParam]) != 0 {
onlyShowRelevant = ctx.FormBool(relevantReposOnlyParam)
}
RenderRepoSearch(ctx, &RepoSearchOptions{
PageSize: setting.UI.ExplorePagingNum,
OwnerID: ownerID,
Private: ctx.Doer != nil,
TplName: tplExploreRepos,
OnlyShowRelevant: onlyShowRelevant,
OnlyShowRelevant: !ctx.FormBool(relevantReposOnlyParam),
})
}

View File

@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/base"
context_module "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
@ -263,7 +264,10 @@ func Rerun(ctx *context_module.Context) {
return
}
actions_service.CreateCommitStatus(ctx, job)
if err := actions_service.CreateCommitStatus(ctx, job); err != nil {
log.Error("Update commit status for job %v failed: %v", job.ID, err)
// go on
}
ctx.JSON(http.StatusOK, struct{}{})
}
@ -304,7 +308,12 @@ func Cancel(ctx *context_module.Context) {
return
}
actions_service.CreateCommitStatus(ctx, jobs...)
for _, job := range jobs {
if err := actions_service.CreateCommitStatus(ctx, job); err != nil {
log.Error("Update commit status for job %v failed: %v", job.ID, err)
// go on
}
}
ctx.JSON(http.StatusOK, struct{}{})
}
@ -340,8 +349,6 @@ func Approve(ctx *context_module.Context) {
return
}
actions_service.CreateCommitStatus(ctx, jobs...)
ctx.JSON(http.StatusOK, struct{}{})
}

View File

@ -64,7 +64,12 @@ func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error {
}
}
CreateCommitStatus(ctx, jobs...)
for _, job := range jobs {
if err := CreateCommitStatus(ctx, job); err != nil {
log.Error("Update commit status for job %v failed: %v", job.ID, err)
// go on
}
}
return nil
}
@ -91,7 +96,10 @@ func CancelAbandonedJobs(ctx context.Context) error {
log.Warn("cancel abandoned job %v: %v", job.ID, err)
// go on
}
CreateCommitStatus(ctx, job)
if err := CreateCommitStatus(ctx, job); err != nil {
log.Error("Update commit status for job %v failed: %v", job.ID, err)
// go on
}
}
return nil

View File

@ -6,80 +6,79 @@ package actions
import (
"context"
"fmt"
"path"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
webhook_module "code.gitea.io/gitea/modules/webhook"
"github.com/nektos/act/pkg/jobparser"
)
// CreateCommitStatus creates a commit status for the given job.
// It won't return an error failed, but will log it, because it's not critical.
func CreateCommitStatus(ctx context.Context, jobs ...*actions_model.ActionRunJob) {
for _, job := range jobs {
if err := createCommitStatus(ctx, job); err != nil {
log.Error("Failed to create commit status for job %d: %v", job.ID, err)
}
}
}
func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) error {
func CreateCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) error {
if err := job.LoadAttributes(ctx); err != nil {
return fmt.Errorf("load run: %w", err)
}
run := job.Run
var (
sha string
event string
sha string
creatorID int64
)
switch run.Event {
case webhook_module.HookEventPush:
event = "push"
payload, err := run.GetPushEventPayload()
if err != nil {
return fmt.Errorf("GetPushEventPayload: %w", err)
}
if payload.HeadCommit == nil {
// Since the payload comes from json data, we should check if it's broken, or it will cause panic
switch {
case payload.Repo == nil:
return fmt.Errorf("repo is missing in event payload")
case payload.Pusher == nil:
return fmt.Errorf("pusher is missing in event payload")
case payload.HeadCommit == nil:
return fmt.Errorf("head commit is missing in event payload")
}
sha = payload.HeadCommit.ID
creatorID = payload.Pusher.ID
case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestSync:
event = "pull_request"
payload, err := run.GetPullRequestEventPayload()
if err != nil {
return fmt.Errorf("GetPullRequestEventPayload: %w", err)
}
if payload.PullRequest == nil {
switch {
case payload.PullRequest == nil:
return fmt.Errorf("pull request is missing in event payload")
} else if payload.PullRequest.Head == nil {
case payload.PullRequest.Head == nil:
return fmt.Errorf("head of pull request is missing in event payload")
case payload.PullRequest.Head.Repository == nil:
return fmt.Errorf("head repository of pull request is missing in event payload")
case payload.PullRequest.Head.Repository.Owner == nil:
return fmt.Errorf("owner of head repository of pull request is missing in evnt payload")
}
sha = payload.PullRequest.Head.Sha
creatorID = payload.PullRequest.Head.Repository.Owner.ID
default:
return nil
}
repo := run.Repo
// TODO: store workflow name as a field in ActionRun to avoid parsing
runName := path.Base(run.WorkflowID)
if wfs, err := jobparser.Parse(job.WorkflowPayload); err == nil && len(wfs) > 0 {
runName = wfs[0].Name
}
ctxname := fmt.Sprintf("%s / %s (%s)", runName, job.Name, event)
ctxname := job.Name
state := toCommitStatus(job.Status)
creator, err := user_model.GetUserByID(ctx, creatorID)
if err != nil {
return fmt.Errorf("GetUserByID: %w", err)
}
if statuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{}); err == nil {
for _, v := range statuses {
if v.Context == ctxname {
if v.State == state {
// no need to update
return nil
}
break
@ -89,26 +88,6 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
return fmt.Errorf("GetLatestCommitStatus: %w", err)
}
description := ""
switch job.Status {
// TODO: if we want support description in different languages, we need to support i18n placeholders in it
case actions_model.StatusSuccess:
description = fmt.Sprintf("Successful in %s", job.Duration())
case actions_model.StatusFailure:
description = fmt.Sprintf("Failing after %s", job.Duration())
case actions_model.StatusCancelled:
description = "Has been cancelled"
case actions_model.StatusSkipped:
description = "Has been skipped"
case actions_model.StatusRunning:
description = "Has started running"
case actions_model.StatusWaiting:
description = "Waiting to run"
case actions_model.StatusBlocked:
description = "Blocked by required conditions"
}
creator := user_model.NewActionsUser()
if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
Repo: repo,
SHA: sha,
@ -116,9 +95,9 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
CommitStatus: &git_model.CommitStatus{
SHA: sha,
TargetURL: run.Link(),
Description: description,
Description: "",
Context: ctxname,
CreatorID: creator.ID,
CreatorID: creatorID,
State: state,
},
}); err != nil {
@ -130,9 +109,9 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
func toCommitStatus(status actions_model.Status) api.CommitStatusState {
switch status {
case actions_model.StatusSuccess, actions_model.StatusSkipped:
case actions_model.StatusSuccess:
return api.CommitStatusSuccess
case actions_model.StatusFailure, actions_model.StatusCancelled:
case actions_model.StatusFailure, actions_model.StatusCancelled, actions_model.StatusSkipped:
return api.CommitStatusFailure
case actions_model.StatusWaiting, actions_model.StatusBlocked:
return api.CommitStatusPending

View File

@ -45,11 +45,11 @@ func jobEmitterQueueHandle(data ...queue.Data) []queue.Data {
}
func checkJobsOfRun(ctx context.Context, runID int64) error {
jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: runID})
if err != nil {
return err
}
if err := db.WithTx(ctx, func(ctx context.Context) error {
return db.WithTx(ctx, func(ctx context.Context) error {
jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: runID})
if err != nil {
return err
}
idToJobs := make(map[string][]*actions_model.ActionRunJob, len(jobs))
for _, job := range jobs {
idToJobs[job.JobID] = append(idToJobs[job.JobID], job)
@ -67,11 +67,7 @@ func checkJobsOfRun(ctx context.Context, runID int64) error {
}
}
return nil
}); err != nil {
return err
}
CreateCommitStatus(ctx, jobs...)
return nil
})
}
type jobStatusResolver struct {

View File

@ -185,7 +185,12 @@ func notify(ctx context.Context, input *notifyInput) error {
if jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: run.ID}); err != nil {
log.Error("FindRunJobs: %v", err)
} else {
CreateCommitStatus(ctx, jobs...)
for _, job := range jobs {
if err := CreateCommitStatus(ctx, job); err != nil {
log.Error("Update commit status for job %v failed: %v", job.ID, err)
// go on
}
}
}
}

View File

@ -208,7 +208,7 @@ func (source *Source) listLdapGroupMemberships(l *ldap.Conn, uid string, applyGr
}
var searchFilter string
if applyGroupFilter && groupFilter != "" {
if applyGroupFilter {
searchFilter = fmt.Sprintf("(&(%s)(%s=%s))", groupFilter, source.GroupMemberUID, ldap.EscapeFilter(uid))
} else {
searchFilter = fmt.Sprintf("(%s=%s)", source.GroupMemberUID, ldap.EscapeFilter(uid))

View File

@ -26,15 +26,12 @@
<input type="hidden" name="language" value="{{$.Language}}">
<div class="ui fluid action input">
<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}…" autofocus>
{{if .PageIsExploreRepositories}}
<input type="hidden" name="only_show_relevant" value="{{.OnlyShowRelevant}}">
{{end}}
<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
</div>
</form>
{{if and .PageIsExploreRepositories .OnlyShowRelevant}}
{{if .OnlyShowRelevant}}
<div class="ui message explore-relevancy-note">
<span data-tooltip-content="{{.locale.Tr "explore.relevant_repositories_tooltip"}}">{{.locale.Tr "explore.relevant_repositories" ((printf "%s%s" $.Link "?only_show_relevant=0")|Escape) | Safe}}</span>
<span data-tooltip-content="{{.locale.Tr "explore.relevant_repositories_tooltip"}}">{{.locale.Tr "explore.relevant_repositories" ((printf "%s%s" $.Link "?no_filter=1")|Escape) | Safe}}</span>
</div>
{{end}}
<div class="ui divider"></div>

View File

@ -43,8 +43,8 @@ func TestAPIPrivateServ(t *testing.T) {
defer cancel()
// Can push to a repo we own
results, extra := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, extra.Error)
results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.Zero(t, results.DeployKeyID)
assert.Equal(t, int64(1), results.KeyID)
@ -56,18 +56,18 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Equal(t, int64(1), results.RepoID)
// Cannot push to a private repo we're not associated with
results, extra = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
assert.Error(t, extra.Error)
results, err = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
assert.Error(t, err)
assert.Empty(t, results)
// Cannot pull from a private repo we're not associated with
results, extra = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
assert.Error(t, extra.Error)
results, err = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
assert.Error(t, err)
assert.Empty(t, results)
// Can pull from a public repo we're not associated with
results, extra = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, extra.Error)
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.Zero(t, results.DeployKeyID)
assert.Equal(t, int64(1), results.KeyID)
@ -79,8 +79,8 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Equal(t, int64(17), results.RepoID)
// Cannot push to a public repo we're not associated with
results, extra = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeWrite, "git-upload-pack", "")
assert.Error(t, extra.Error)
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeWrite, "git-upload-pack", "")
assert.Error(t, err)
assert.Empty(t, results)
// Add reading deploy key
@ -88,8 +88,8 @@ func TestAPIPrivateServ(t *testing.T) {
assert.NoError(t, err)
// Can pull from repo we're a deploy key for
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, extra.Error)
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
@ -101,18 +101,18 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Equal(t, int64(19), results.RepoID)
// Cannot push to a private repo with reading key
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
assert.Error(t, extra.Error)
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
assert.Error(t, err)
assert.Empty(t, results)
// Cannot pull from a private repo we're not associated with
results, extra = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
assert.Error(t, extra.Error)
results, err = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
assert.Error(t, err)
assert.Empty(t, results)
// Cannot pull from a public repo we're not associated with
results, extra = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
assert.Error(t, extra.Error)
results, err = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
assert.Error(t, err)
assert.Empty(t, results)
// Add writing deploy key
@ -120,13 +120,13 @@ func TestAPIPrivateServ(t *testing.T) {
assert.NoError(t, err)
// Cannot push to a private repo with reading key
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
assert.Error(t, extra.Error)
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
assert.Error(t, err)
assert.Empty(t, results)
// Can pull from repo we're a writing deploy key for
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, extra.Error)
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
@ -138,8 +138,8 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Equal(t, int64(20), results.RepoID)
// Can push to repo we're a writing deploy key for
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, extra.Error)
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)