mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-15 00:01:25 -04:00
Compare commits
5 Commits
79e7a6ec1e
...
7422503341
Author | SHA1 | Date | |
---|---|---|---|
|
7422503341 | ||
|
3e8db31a5b | ||
|
e57e1144c5 | ||
|
ed5e7d03c6 | ||
|
f4538791f5 |
@ -60,13 +60,13 @@ func main() {
|
||||
// generate data
|
||||
buf, err := generate()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatalf("generate err: %v", err)
|
||||
}
|
||||
|
||||
// write
|
||||
err = os.WriteFile(*flagOut, buf, 0o644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatalf("WriteFile err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
144
cmd/hook.go
144
cmd/hook.go
@ -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("hooks/pre-receive.log", c.Bool("debug"))
|
||||
setup(ctx, c.Bool("debug"))
|
||||
|
||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
||||
return fail(`Rejecting changes as Gitea environment not set.
|
||||
return fail(ctx, `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,14 +257,9 @@ Gitea or set your environment appropriately.`, "")
|
||||
hookOptions.OldCommitIDs = oldCommitIDs
|
||||
hookOptions.NewCommitIDs = newCommitIDs
|
||||
hookOptions.RefFullNames = refFullNames
|
||||
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, "")
|
||||
extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
|
||||
if extra.HasError() {
|
||||
return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error)
|
||||
}
|
||||
count = 0
|
||||
lastline = 0
|
||||
@ -285,12 +280,9 @@ Gitea or set your environment appropriately.`, "")
|
||||
|
||||
fmt.Fprintf(out, " Checking %d references\n", count)
|
||||
|
||||
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, "")
|
||||
extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
|
||||
if extra.HasError() {
|
||||
return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error)
|
||||
}
|
||||
} else if lastline > 0 {
|
||||
fmt.Fprintf(out, "\n")
|
||||
@ -309,7 +301,7 @@ func runHookPostReceive(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("hooks/post-receive.log", c.Bool("debug"))
|
||||
setup(ctx, 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 {
|
||||
@ -323,7 +315,7 @@ func runHookPostReceive(c *cli.Context) error {
|
||||
|
||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
||||
return fail(`Rejecting changes as Gitea environment not set.
|
||||
return fail(ctx, `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.`, "")
|
||||
}
|
||||
@ -394,11 +386,11 @@ Gitea or set your environment appropriately.`, "")
|
||||
hookOptions.OldCommitIDs = oldCommitIDs
|
||||
hookOptions.NewCommitIDs = newCommitIDs
|
||||
hookOptions.RefFullNames = refFullNames
|
||||
resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
||||
if resp == nil {
|
||||
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
||||
if extra.HasError() {
|
||||
_ = dWriter.Close()
|
||||
hookPrintResults(results)
|
||||
return fail("Internal Server Error", err)
|
||||
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
|
||||
}
|
||||
wasEmpty = wasEmpty || resp.RepoWasEmpty
|
||||
results = append(results, resp.Results...)
|
||||
@ -409,9 +401,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
|
||||
err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
|
||||
if err != nil {
|
||||
return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
|
||||
extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
|
||||
if extra.HasError() {
|
||||
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(out, "Processed %d references in total\n", total)
|
||||
@ -427,11 +419,11 @@ Gitea or set your environment appropriately.`, "")
|
||||
|
||||
fmt.Fprintf(out, " Processing %d references\n", count)
|
||||
|
||||
resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
||||
resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
|
||||
if resp == nil {
|
||||
_ = dWriter.Close()
|
||||
hookPrintResults(results)
|
||||
return fail("Internal Server Error", err)
|
||||
return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
|
||||
}
|
||||
wasEmpty = wasEmpty || resp.RepoWasEmpty
|
||||
results = append(results, resp.Results...)
|
||||
@ -440,9 +432,9 @@ Gitea or set your environment appropriately.`, "")
|
||||
|
||||
if wasEmpty && masterPushed {
|
||||
// We need to tell the repo to reset the default branch to master
|
||||
err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
|
||||
if err != nil {
|
||||
return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
|
||||
extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
|
||||
if extra.HasError() {
|
||||
return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
|
||||
}
|
||||
}
|
||||
_ = dWriter.Close()
|
||||
@ -485,22 +477,22 @@ func pushOptions() map[string]string {
|
||||
}
|
||||
|
||||
func runHookProcReceive(c *cli.Context) error {
|
||||
setup("hooks/proc-receive.log", c.Bool("debug"))
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"))
|
||||
|
||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
||||
return fail(`Rejecting changes as Gitea environment not set.
|
||||
return fail(ctx, `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("Internal Server Error", "git not support proc-receive.")
|
||||
return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.")
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
@ -515,7 +507,7 @@ Gitea or set your environment appropriately.`, "")
|
||||
// H: PKT-LINE(version=1\0push-options...)
|
||||
// H: flush-pkt
|
||||
|
||||
rs, err := readPktLine(reader, pktLineTypeData)
|
||||
rs, err := readPktLine(ctx, reader, pktLineTypeData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -530,19 +522,19 @@ Gitea or set your environment appropriately.`, "")
|
||||
|
||||
index := bytes.IndexByte(rs.Data, byte(0))
|
||||
if index >= len(rs.Data) {
|
||||
return fail("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
|
||||
return fail(ctx, "Protocol: format 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("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
|
||||
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
|
||||
}
|
||||
}
|
||||
|
||||
if string(rs.Data[0:index]) != VersionHead {
|
||||
return fail("Internal Server Error", "Received unsupported version: %s", string(rs.Data[0:index]))
|
||||
return fail(ctx, "Protocol: version error", "Received unsupported version: %s", string(rs.Data[0:index]))
|
||||
}
|
||||
requestOptions = strings.Split(string(rs.Data[index+1:]), " ")
|
||||
|
||||
@ -555,17 +547,17 @@ Gitea or set your environment appropriately.`, "")
|
||||
}
|
||||
response = append(response, '\n')
|
||||
|
||||
_, err = readPktLine(reader, pktLineTypeFlush)
|
||||
_, err = readPktLine(ctx, reader, pktLineTypeFlush)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeDataPktLine(os.Stdout, response)
|
||||
err = writeDataPktLine(ctx, os.Stdout, response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeFlushPktLine(os.Stdout)
|
||||
err = writeFlushPktLine(ctx, os.Stdout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -588,7 +580,7 @@ Gitea or set your environment appropriately.`, "")
|
||||
|
||||
for {
|
||||
// note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
|
||||
rs, err = readPktLine(reader, pktLineTypeUnknow)
|
||||
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -609,7 +601,7 @@ Gitea or set your environment appropriately.`, "")
|
||||
|
||||
if hasPushOptions {
|
||||
for {
|
||||
rs, err = readPktLine(reader, pktLineTypeUnknow)
|
||||
rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -626,9 +618,9 @@ Gitea or set your environment appropriately.`, "")
|
||||
}
|
||||
|
||||
// 3. run hook
|
||||
resp, err := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
|
||||
if err != nil {
|
||||
return fail("Internal Server Error", "run proc-receive hook failed :%v", err)
|
||||
resp, extra := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
|
||||
if extra.HasError() {
|
||||
return fail(ctx, extra.UserMsg, "HookProcReceive failed: %v", extra.Error)
|
||||
}
|
||||
|
||||
// 4. response result to service
|
||||
@ -649,7 +641,7 @@ Gitea or set your environment appropriately.`, "")
|
||||
|
||||
for _, rs := range resp.Results {
|
||||
if len(rs.Err) > 0 {
|
||||
err = writeDataPktLine(os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
|
||||
err = writeDataPktLine(ctx, os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -657,43 +649,43 @@ Gitea or set your environment appropriately.`, "")
|
||||
}
|
||||
|
||||
if rs.IsNotMatched {
|
||||
err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
|
||||
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = writeDataPktLine(os.Stdout, []byte("option fall-through"))
|
||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option fall-through"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
|
||||
err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = writeDataPktLine(os.Stdout, []byte("option refname "+rs.Ref))
|
||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option refname "+rs.Ref))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rs.OldOID != git.EmptySHA {
|
||||
err = writeDataPktLine(os.Stdout, []byte("option old-oid "+rs.OldOID))
|
||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = writeDataPktLine(os.Stdout, []byte("option new-oid "+rs.NewOID))
|
||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option new-oid "+rs.NewOID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rs.IsForcePush {
|
||||
err = writeDataPktLine(os.Stdout, []byte("option forced-update"))
|
||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option forced-update"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
err = writeFlushPktLine(os.Stdout)
|
||||
err = writeFlushPktLine(ctx, os.Stdout)
|
||||
|
||||
return err
|
||||
}
|
||||
@ -718,7 +710,7 @@ type gitPktLine struct {
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
|
||||
func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
|
||||
var (
|
||||
err error
|
||||
r *gitPktLine
|
||||
@ -729,33 +721,33 @@ func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error)
|
||||
for i := 0; i < 4; i++ {
|
||||
lengthBytes[i], err = in.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fail("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
|
||||
return nil, fail(ctx, "Protocol: stdin 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("Internal Server Error", "Pkt-Line format is wrong :%v", err)
|
||||
return nil, fail(ctx, "Protocol: format parse error", "Pkt-Line format is wrong :%v", err)
|
||||
}
|
||||
|
||||
if r.Length == 0 {
|
||||
if requestType == pktLineTypeData {
|
||||
return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
|
||||
return nil, fail(ctx, "Protocol: format data error", "Pkt-Line format is wrong")
|
||||
}
|
||||
r.Type = pktLineTypeFlush
|
||||
return r, nil
|
||||
}
|
||||
|
||||
if r.Length <= 4 || r.Length > 65520 || requestType == pktLineTypeFlush {
|
||||
return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
|
||||
return nil, fail(ctx, "Protocol: format length 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("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
|
||||
return nil, fail(ctx, "Protocol: data error", "Pkt-Line: read stdin failed : %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -764,19 +756,15 @@ func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func writeFlushPktLine(out io.Writer) error {
|
||||
func writeFlushPktLine(ctx context.Context, out io.Writer) error {
|
||||
l, err := out.Write([]byte("0000"))
|
||||
if err != nil {
|
||||
return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
|
||||
if err != nil || l != 4 {
|
||||
return fail(ctx, "Protocol: write 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(out io.Writer, data []byte) error {
|
||||
func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error {
|
||||
hexchar := []byte("0123456789abcdef")
|
||||
hex := func(n uint64) byte {
|
||||
return hexchar[(n)&15]
|
||||
@ -790,19 +778,13 @@ func writeDataPktLine(out io.Writer, data []byte) error {
|
||||
tmp[3] = hex(length)
|
||||
|
||||
lr, err := out.Write(tmp)
|
||||
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)
|
||||
if err != nil || lr != 4 {
|
||||
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
|
||||
}
|
||||
|
||||
lr, err = out.Write(data)
|
||||
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)
|
||||
if err != nil || int(length-4) != lr {
|
||||
return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -6,6 +6,7 @@ package cmd
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -14,27 +15,28 @@ import (
|
||||
|
||||
func TestPktLine(t *testing.T) {
|
||||
// test read
|
||||
ctx := context.Background()
|
||||
s := strings.NewReader("0000")
|
||||
r := bufio.NewReader(s)
|
||||
result, err := readPktLine(r, pktLineTypeFlush)
|
||||
result, err := readPktLine(ctx, r, pktLineTypeFlush)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, pktLineTypeFlush, result.Type)
|
||||
|
||||
s = strings.NewReader("0006a\n")
|
||||
r = bufio.NewReader(s)
|
||||
result, err = readPktLine(r, pktLineTypeData)
|
||||
result, err = readPktLine(ctx, 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(w)
|
||||
err = writeFlushPktLine(ctx, w)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []byte("0000"), w.Bytes())
|
||||
|
||||
w.Reset()
|
||||
err = writeDataPktLine(w, []byte("a\nb"))
|
||||
err = writeDataPktLine(ctx, w, []byte("a\nb"))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []byte("0007a\nb"), w.Bytes())
|
||||
}
|
||||
|
@ -64,11 +64,12 @@ func runKeys(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("keys.log", false)
|
||||
setup(ctx, false)
|
||||
|
||||
authorizedString, err := private.AuthorizedPublicKeyByContent(ctx, content)
|
||||
if err != nil {
|
||||
return err
|
||||
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
|
||||
}
|
||||
fmt.Println(strings.TrimSpace(authorizedString))
|
||||
return nil
|
||||
|
@ -5,7 +5,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@ -43,13 +42,10 @@ func runSendMail(c *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
status, message := private.SendEmail(ctx, subject, body, nil)
|
||||
if status != http.StatusOK {
|
||||
fmt.Printf("error: %s\n", message)
|
||||
return nil
|
||||
respText, extra := private.SendEmail(ctx, subject, body, nil)
|
||||
if extra.HasError() {
|
||||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
fmt.Printf("Success: %s\n", message)
|
||||
|
||||
_, _ = fmt.Printf("Sent %s email(s) to all users\n", respText)
|
||||
return nil
|
||||
}
|
||||
|
@ -4,8 +4,6 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@ -103,57 +101,34 @@ func runShutdown(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
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
|
||||
setup(ctx, c.Bool("debug"))
|
||||
extra := private.Shutdown(ctx)
|
||||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runRestart(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
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
|
||||
setup(ctx, c.Bool("debug"))
|
||||
extra := private.Restart(ctx)
|
||||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runFlushQueues(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
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
|
||||
setup(ctx, c.Bool("debug"))
|
||||
extra := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
|
||||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runProcesses(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
@ -191,27 +190,25 @@ var (
|
||||
)
|
||||
|
||||
func runRemoveLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"))
|
||||
group := c.String("group")
|
||||
if len(group) == 0 {
|
||||
group = log.DEFAULT
|
||||
}
|
||||
name := c.Args().First()
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
statusCode, msg := private.RemoveLogger(ctx, group, name)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
extra := private.RemoveLogger(ctx, group, name)
|
||||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runAddSMTPLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "smtp"
|
||||
if c.IsSet("host") {
|
||||
@ -242,7 +239,10 @@ func runAddSMTPLogger(c *cli.Context) error {
|
||||
}
|
||||
|
||||
func runAddConnLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "conn"
|
||||
vals["net"] = "tcp"
|
||||
@ -269,7 +269,10 @@ func runAddConnLogger(c *cli.Context) error {
|
||||
}
|
||||
|
||||
func runAddFileLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "file"
|
||||
if c.IsSet("filename") {
|
||||
@ -299,7 +302,10 @@ func runAddFileLogger(c *cli.Context) error {
|
||||
}
|
||||
|
||||
func runAddConsoleLogger(c *cli.Context) error {
|
||||
setup("manager", c.Bool("debug"))
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup(ctx, c.Bool("debug"))
|
||||
vals := map[string]interface{}{}
|
||||
mode := "console"
|
||||
if c.IsSet("stderr") && c.Bool("stderr") {
|
||||
@ -338,28 +344,17 @@ func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) e
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
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
|
||||
extra := private.AddLogger(ctx, group, name, mode, vals)
|
||||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
||||
func runPauseLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("manager", c.Bool("debug"))
|
||||
statusCode, msg := private.PauseLogging(ctx)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
setup(ctx, c.Bool("debug"))
|
||||
userMsg := private.PauseLogging(ctx)
|
||||
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -367,14 +362,9 @@ func runResumeLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("manager", c.Bool("debug"))
|
||||
statusCode, msg := private.ResumeLogging(ctx)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
setup(ctx, c.Bool("debug"))
|
||||
userMsg := private.ResumeLogging(ctx)
|
||||
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -382,28 +372,17 @@ func runReleaseReopenLogging(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
setup("manager", c.Bool("debug"))
|
||||
statusCode, msg := private.ReleaseReopenLogging(ctx)
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
setup(ctx, c.Bool("debug"))
|
||||
userMsg := private.ReleaseReopenLogging(ctx)
|
||||
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runSetLogSQL(c *cli.Context) error {
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
setup("manager", c.Bool("debug"))
|
||||
setup(ctx, c.Bool("debug"))
|
||||
|
||||
statusCode, msg := private.SetLogSQL(ctx, !c.Bool("off"))
|
||||
switch statusCode {
|
||||
case http.StatusInternalServerError:
|
||||
return fail("InternalServerError", msg)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, msg)
|
||||
return nil
|
||||
extra := private.SetLogSQL(ctx, !c.Bool("off"))
|
||||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
@ -4,11 +4,8 @@
|
||||
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"
|
||||
|
||||
@ -60,7 +57,7 @@ func runRestoreRepository(c *cli.Context) error {
|
||||
if s := c.String("units"); s != "" {
|
||||
units = strings.Split(s, ",")
|
||||
}
|
||||
statusCode, errStr := private.RestoreRepo(
|
||||
extra := private.RestoreRepo(
|
||||
ctx,
|
||||
c.String("repo_dir"),
|
||||
c.String("owner_name"),
|
||||
@ -68,10 +65,5 @@ func runRestoreRepository(c *cli.Context) error {
|
||||
units,
|
||||
c.Bool("validation"),
|
||||
)
|
||||
if statusCode == http.StatusOK {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Fatal("Failed to restore repository: %v", errStr)
|
||||
return errors.New(errStr)
|
||||
return handleCliResponseExtra(extra)
|
||||
}
|
||||
|
97
cmd/serv.go
97
cmd/serv.go
@ -7,7 +7,6 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -16,6 +15,7 @@ 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(logPath string, debug bool) {
|
||||
func setup(ctx context.Context, debug bool) {
|
||||
_ = log.DelLogger("console")
|
||||
if debug {
|
||||
_ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`)
|
||||
@ -72,15 +72,15 @@ func setup(logPath string, 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("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(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)
|
||||
} else {
|
||||
_ = fail("Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
|
||||
_ = fail(ctx, "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("Failed to init git", "Failed to init git, err: %v", err)
|
||||
_ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,32 +94,54 @@ var (
|
||||
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
|
||||
)
|
||||
|
||||
func fail(userMessage, logMessage string, args ...interface{}) error {
|
||||
// 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)"
|
||||
}
|
||||
|
||||
// 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 len(logMessage) > 0 {
|
||||
if logMsgFmt != "" {
|
||||
logMsg := fmt.Sprintf(logMsgFmt, args...)
|
||||
if !setting.IsProd {
|
||||
_, _ = fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
|
||||
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", logMsg)
|
||||
}
|
||||
if userMessage != "" {
|
||||
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
|
||||
logMsg = userMessage + " " + logMsg
|
||||
} else {
|
||||
logMsg = userMessage + ". " + logMsg
|
||||
}
|
||||
}
|
||||
ctx, cancel := installSignals()
|
||||
defer cancel()
|
||||
|
||||
if len(logMessage) > 0 {
|
||||
_ = private.SSHLog(ctx, true, fmt.Sprintf(logMessage+": ", args...))
|
||||
_ = private.SSHLog(ctx, true, logMsg)
|
||||
}
|
||||
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("serv.log", c.Bool("debug"))
|
||||
setup(ctx, c.Bool("debug"))
|
||||
|
||||
if setting.SSH.Disabled {
|
||||
println("Gitea: SSH has been disabled")
|
||||
@ -135,18 +157,18 @@ func runServ(c *cli.Context) error {
|
||||
|
||||
keys := strings.Split(c.Args()[0], "-")
|
||||
if len(keys) != 2 || keys[0] != "key" {
|
||||
return fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
|
||||
return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args()[0])
|
||||
}
|
||||
keyID, err := strconv.ParseInt(keys[1], 10, 64)
|
||||
if err != nil {
|
||||
return fail("Key ID format error", "Invalid key argument: %s", c.Args()[1])
|
||||
return fail(ctx, "Key ID parsing 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("Internal error", "Failed to check provided key: %v", err)
|
||||
return fail(ctx, "Key check failed", "Failed to check provided key: %v", err)
|
||||
}
|
||||
switch key.Type {
|
||||
case asymkey_model.KeyTypeDeploy:
|
||||
@ -164,7 +186,7 @@ func runServ(c *cli.Context) error {
|
||||
|
||||
words, err := shellquote.Split(cmd)
|
||||
if err != nil {
|
||||
return fail("Error parsing arguments", "Failed to parse arguments: %v", err)
|
||||
return fail(ctx, "Error parsing arguments", "Failed to parse arguments: %v", err)
|
||||
}
|
||||
|
||||
if len(words) < 2 {
|
||||
@ -175,7 +197,7 @@ func runServ(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fail("Too few arguments", "Too few arguments in cmd: %s", cmd)
|
||||
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
|
||||
}
|
||||
|
||||
verb := words[0]
|
||||
@ -187,7 +209,7 @@ func runServ(c *cli.Context) error {
|
||||
var lfsVerb string
|
||||
if verb == lfsAuthenticateVerb {
|
||||
if !setting.LFS.StartServer {
|
||||
return fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
|
||||
return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
|
||||
}
|
||||
|
||||
if len(words) > 2 {
|
||||
@ -200,37 +222,37 @@ func runServ(c *cli.Context) error {
|
||||
|
||||
rr := strings.SplitN(repoPath, "/", 2)
|
||||
if len(rr) != 2 {
|
||||
return fail("Invalid repository path", "Invalid repository path: %v", repoPath)
|
||||
return fail(ctx, "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("Invalid repo name", "Invalid repo name: %s", reponame)
|
||||
return fail(ctx, "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("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
|
||||
return fail(ctx, "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("Internal Server Error", "Unable to start CPU profile: %v", err)
|
||||
return fail(ctx, "Unable to start CPU profiler", "Unable to start CPU profile: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
stopCPUProfiler()
|
||||
err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
|
||||
if err != nil {
|
||||
_ = fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
|
||||
_ = fail(ctx, "Unable to dump Mem profile", "Unable to dump Mem Profile: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
requestedMode, has := allowedCommands[verb]
|
||||
if !has {
|
||||
return fail("Unknown git command", "Unknown git command %s", verb)
|
||||
return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
|
||||
}
|
||||
|
||||
if verb == lfsAuthenticateVerb {
|
||||
@ -239,20 +261,13 @@ func runServ(c *cli.Context) error {
|
||||
} else if lfsVerb == "download" {
|
||||
requestedMode = perm.AccessModeRead
|
||||
} else {
|
||||
return fail("Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
|
||||
return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
|
||||
if extra.HasError() {
|
||||
return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
|
||||
}
|
||||
|
||||
// LFS token authentication
|
||||
@ -274,7 +289,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("Internal error", "Failed to sign JWT token: %v", err)
|
||||
return fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
|
||||
}
|
||||
|
||||
tokenAuthentication := &git_model.LFSTokenResponse{
|
||||
@ -286,7 +301,7 @@ func runServ(c *cli.Context) error {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
err = enc.Encode(tokenAuthentication)
|
||||
if err != nil {
|
||||
return fail("Internal error", "Failed to encode LFS json response: %v", err)
|
||||
return fail(ctx, "Failed to encode LFS json response", "Failed to encode LFS json response: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -332,13 +347,13 @@ func runServ(c *cli.Context) error {
|
||||
gitcmd.Env = append(gitcmd.Env, git.CommonCmdServEnvs()...)
|
||||
|
||||
if err = gitcmd.Run(); err != nil {
|
||||
return fail("Internal error", "Failed to execute git command: %v", err)
|
||||
return fail(ctx, "Failed to execute git command", "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("Internal error", "UpdatePublicKeyInRepo: %v", err)
|
||||
return fail(ctx, "Failed to update public key", "UpdatePublicKeyInRepo: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1238,6 +1238,10 @@ 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
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -226,11 +226,13 @@ 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`)
|
||||
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -68,6 +69,11 @@ 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
|
||||
@ -138,11 +144,11 @@ func (r *Request) getResponse() (*http.Response, error) {
|
||||
r.Body(paramBody)
|
||||
}
|
||||
|
||||
url, err := url.Parse(r.url)
|
||||
var err error
|
||||
r.req.URL, err = url.Parse(r.url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.req.URL = url
|
||||
|
||||
trans := r.setting.Transport
|
||||
if trans == nil {
|
||||
@ -194,3 +200,7 @@ 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)
|
||||
}
|
||||
|
@ -5,14 +5,11 @@ package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
@ -99,126 +96,46 @@ type HookProcReceiveRefResult struct {
|
||||
}
|
||||
|
||||
// HookPreReceive check whether the provided commits are allowed
|
||||
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, ""
|
||||
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
|
||||
}
|
||||
|
||||
// HookPostReceive updates services and users
|
||||
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, ""
|
||||
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{})
|
||||
}
|
||||
|
||||
// HookProcReceive proc-receive hook
|
||||
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),
|
||||
)
|
||||
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))
|
||||
|
||||
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
|
||||
req := newInternalRequest(ctx, reqURL, "POST", opts)
|
||||
req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
|
||||
return requestJSONResp(req, &HookProcReceiveResult{})
|
||||
}
|
||||
|
||||
// SetDefaultBranch will set the default branch to the provided branch for the provided repository
|
||||
func SetDefaultBranch(ctx context.Context, ownerName, repoName, branch string) error {
|
||||
func SetDefaultBranch(ctx context.Context, ownerName, repoName, branch string) ResponseExtra {
|
||||
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")
|
||||
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
|
||||
return requestJSONUserMsg(req, "")
|
||||
}
|
||||
|
||||
// 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")
|
||||
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
|
||||
req := newInternalRequest(ctx, reqURL, "POST", &SSHLogOption{IsError: isErr, Message: msg})
|
||||
_, extra := requestJSONResp(req, &responseText{})
|
||||
return extra.Error
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
@ -19,29 +20,10 @@ import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
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
|
||||
// Response is used for internal request response (for user message and error message)
|
||||
type Response struct {
|
||||
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
|
||||
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.
|
||||
}
|
||||
|
||||
func getClientIP() string {
|
||||
@ -52,11 +34,21 @@ func getClientIP() string {
|
||||
return strings.Fields(sshConnEnv)[0]
|
||||
}
|
||||
|
||||
func newInternalRequest(ctx context.Context, url, method string) *httplib.Request {
|
||||
req := newRequest(ctx, url, method, getClientIP()).SetTLSClientConfig(&tls.Config{
|
||||
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,
|
||||
})
|
||||
|
||||
if setting.Protocol == setting.HTTPUnix {
|
||||
req.SetTransport(&http.Transport{
|
||||
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||
@ -90,5 +82,15 @@ func newInternalRequest(ctx context.Context, url, method string) *httplib.Reques
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ package private
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
@ -16,39 +14,18 @@ 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)
|
||||
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
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
_, extra := requestJSONResp(req, &responseText{})
|
||||
return extra.Error
|
||||
}
|
||||
|
||||
// AuthorizedPublicKeyByContent searches content as prefix (leak e-mail part)
|
||||
// and returns public key found.
|
||||
func AuthorizedPublicKeyByContent(ctx context.Context, content string) (string, error) {
|
||||
func AuthorizedPublicKeyByContent(ctx context.Context, content string) (string, ResponseExtra) {
|
||||
// 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, 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
|
||||
resp, extra := requestJSONResp(req, &responseText{})
|
||||
return resp.Text, extra
|
||||
}
|
||||
|
@ -5,11 +5,7 @@ package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
@ -21,38 +17,18 @@ 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 its supposed to send an email to every
|
||||
// user present in DB
|
||||
func SendEmail(ctx context.Context, subject, message string, to []string) (int, string) {
|
||||
// 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) {
|
||||
reqURL := setting.LocalURL + "api/internal/mail/send"
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
req = req.Header("Content-Type", "application/json")
|
||||
jsonBytes, _ := json.Marshal(Email{
|
||||
req := newInternalRequest(ctx, reqURL, "POST", 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()
|
||||
|
||||
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)
|
||||
resp, extra := requestJSONResp(req, &responseText{})
|
||||
return resp.Text, extra
|
||||
}
|
||||
|
@ -12,44 +12,21 @@ 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) (int, string) {
|
||||
func Shutdown(ctx context.Context) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/manager/shutdown"
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
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"
|
||||
return requestJSONUserMsg(req, "Shutting down")
|
||||
}
|
||||
|
||||
// Restart calls the internal restart function
|
||||
func Restart(ctx context.Context) (int, string) {
|
||||
func Restart(ctx context.Context) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/manager/restart"
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
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"
|
||||
return requestJSONUserMsg(req, "Restarting")
|
||||
}
|
||||
|
||||
// FlushOptions represents the options for the flush call
|
||||
@ -59,102 +36,41 @@ type FlushOptions struct {
|
||||
}
|
||||
|
||||
// FlushQueues calls the internal flush-queues function
|
||||
func FlushQueues(ctx context.Context, timeout time.Duration, nonBlocking bool) (int, string) {
|
||||
func FlushQueues(ctx context.Context, timeout time.Duration, nonBlocking bool) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/manager/flush-queues"
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
req := newInternalRequest(ctx, reqURL, "POST", FlushOptions{Timeout: timeout, NonBlocking: nonBlocking})
|
||||
if timeout > 0 {
|
||||
req.SetTimeout(timeout+10*time.Second, timeout+10*time.Second)
|
||||
req.SetReadWriteTimeout(timeout + 10*time.Second)
|
||||
}
|
||||
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"
|
||||
return requestJSONUserMsg(req, "Flushed")
|
||||
}
|
||||
|
||||
// PauseLogging pauses logging
|
||||
func PauseLogging(ctx context.Context) (int, string) {
|
||||
func PauseLogging(ctx context.Context) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/manager/pause-logging"
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
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"
|
||||
return requestJSONUserMsg(req, "Logging Paused")
|
||||
}
|
||||
|
||||
// ResumeLogging resumes logging
|
||||
func ResumeLogging(ctx context.Context) (int, string) {
|
||||
func ResumeLogging(ctx context.Context) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/manager/resume-logging"
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
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"
|
||||
return requestJSONUserMsg(req, "Logging Restarted")
|
||||
}
|
||||
|
||||
// ReleaseReopenLogging releases and reopens logging files
|
||||
func ReleaseReopenLogging(ctx context.Context) (int, string) {
|
||||
func ReleaseReopenLogging(ctx context.Context) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/manager/release-and-reopen-logging"
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
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"
|
||||
return requestJSONUserMsg(req, "Logging Restarted")
|
||||
}
|
||||
|
||||
// SetLogSQL sets database logging
|
||||
func SetLogSQL(ctx context.Context, on bool) (int, string) {
|
||||
func SetLogSQL(ctx context.Context, on bool) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/manager/set-log-sql?on=" + strconv.FormatBool(on)
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
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"
|
||||
return requestJSONUserMsg(req, "Log SQL setting set")
|
||||
}
|
||||
|
||||
// LoggerOptions represents the options for the add logger call
|
||||
@ -166,67 +82,32 @@ type LoggerOptions struct {
|
||||
}
|
||||
|
||||
// AddLogger adds a logger
|
||||
func AddLogger(ctx context.Context, group, name, mode string, config map[string]interface{}) (int, string) {
|
||||
func AddLogger(ctx context.Context, group, name, mode string, config map[string]interface{}) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/manager/add-logger"
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
req = req.Header("Content-Type", "application/json")
|
||||
jsonBytes, _ := json.Marshal(LoggerOptions{
|
||||
req := newInternalRequest(ctx, reqURL, "POST", LoggerOptions{
|
||||
Group: group,
|
||||
Name: name,
|
||||
Mode: mode,
|
||||
Config: config,
|
||||
})
|
||||
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"
|
||||
return requestJSONUserMsg(req, "Added")
|
||||
}
|
||||
|
||||
// RemoveLogger removes a logger
|
||||
func RemoveLogger(ctx context.Context, group, name string) (int, string) {
|
||||
func RemoveLogger(ctx context.Context, group, name string) ResponseExtra {
|
||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/manager/remove-logger/%s/%s", url.PathEscape(group), url.PathEscape(name))
|
||||
|
||||
req := newInternalRequest(ctx, reqURL, "POST")
|
||||
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"
|
||||
return requestJSONUserMsg(req, "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) (int, string) {
|
||||
func Processes(ctx context.Context, out io.Writer, flat, noSystem, stacktraces, json bool, cancel string) ResponseExtra {
|
||||
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")
|
||||
resp, err := req.Response()
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
|
||||
callback := func(resp *http.Response, extra *ResponseExtra) {
|
||||
_, extra.Error = io.Copy(out, resp.Body)
|
||||
}
|
||||
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, ""
|
||||
_, extra := requestJSONResp(req, &callback)
|
||||
return extra
|
||||
}
|
||||
|
135
modules/private/request.go
Normal file
135
modules/private/request.go
Normal file
@ -0,0 +1,135 @@
|
||||
// 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
|
||||
}
|
@ -6,11 +6,8 @@ package private
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
@ -24,39 +21,16 @@ type RestoreParams struct {
|
||||
}
|
||||
|
||||
// RestoreRepo calls the internal RestoreRepo function
|
||||
func RestoreRepo(ctx context.Context, repoDir, ownerName, repoName string, units []string, validation bool) (int, string) {
|
||||
func RestoreRepo(ctx context.Context, repoDir, ownerName, repoName string, units []string, validation bool) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/restore_repo"
|
||||
|
||||
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{
|
||||
req := newInternalRequest(ctx, reqURL, "POST", RestoreParams{
|
||||
RepoDir: repoDir,
|
||||
OwnerName: ownerName,
|
||||
RepoName: repoName,
|
||||
Units: units,
|
||||
Validation: validation,
|
||||
})
|
||||
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)
|
||||
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))
|
||||
}
|
||||
|
@ -6,13 +6,11 @@ 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"
|
||||
)
|
||||
|
||||
@ -24,20 +22,11 @@ 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)
|
||||
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
|
||||
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
|
||||
}
|
||||
return keyAndOwner.Key, keyAndOwner.Owner, nil
|
||||
}
|
||||
@ -56,53 +45,19 @@ 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, error) {
|
||||
func ServCommand(ctx context.Context, keyID int64, ownerName, repoName string, mode perm.AccessMode, verbs ...string) (*ServCommandResults, ResponseExtra) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
req := newInternalRequest(ctx, reqURL, "GET")
|
||||
return requestJSONResp(req, &ServCommandResults{})
|
||||
}
|
||||
|
@ -139,6 +139,9 @@ 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])
|
||||
|
@ -1250,6 +1250,7 @@ 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
|
||||
|
@ -1202,6 +1202,7 @@ 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
|
||||
|
@ -1259,6 +1259,7 @@ 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=Μη έγκυρα πρότυπα έχουν αγνοηθεί
|
||||
|
@ -1224,6 +1224,7 @@ 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
|
||||
|
@ -1117,6 +1117,7 @@ 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=بدون شاخه/برچسب مشخص
|
||||
|
@ -867,6 +867,7 @@ 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
|
||||
|
@ -971,6 +971,7 @@ 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
|
||||
|
@ -774,6 +774,7 @@ 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
|
||||
|
@ -1211,6 +1211,7 @@ 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
|
||||
|
@ -1271,6 +1271,7 @@ 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=無効なテンプレートが無視されました
|
||||
|
@ -1259,6 +1259,7 @@ 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
|
||||
|
@ -1211,6 +1211,7 @@ 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
|
||||
|
@ -1120,6 +1120,7 @@ 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
|
||||
|
@ -1259,6 +1259,7 @@ 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
|
||||
|
@ -1068,6 +1068,7 @@ 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
|
||||
@ -1271,10 +1272,12 @@ 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
|
||||
@ -1488,6 +1491,9 @@ 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
|
||||
|
@ -1177,6 +1177,7 @@ 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=Не указана ветка или тэг
|
||||
|
@ -1076,6 +1076,7 @@ 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=කිසිදු ශාඛාව/ටැග නිශ්චිතව දක්වා
|
||||
|
@ -1022,6 +1022,7 @@ 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
|
||||
|
@ -918,6 +918,7 @@ 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
|
||||
|
@ -1232,6 +1232,7 @@ 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=Aç
|
||||
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
|
||||
|
@ -1126,6 +1126,7 @@ 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=Не вказана гілка або тег
|
||||
|
@ -1271,6 +1271,7 @@ 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=已忽略无效模板
|
||||
|
@ -249,6 +249,7 @@ 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 檢查更新。
|
||||
|
||||
@ -520,8 +521,14 @@ 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=目標分支不存在
|
||||
|
||||
@ -986,6 +993,7 @@ 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。
|
||||
@ -1167,6 +1175,7 @@ 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=作者
|
||||
@ -1262,6 +1271,7 @@ 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=已忽略無效的範本
|
||||
@ -2466,6 +2476,7 @@ 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=這個團隊沒有任何成員。
|
||||
@ -2495,6 +2506,7 @@ 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=系統狀態
|
||||
@ -2614,6 +2626,7 @@ 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=篩選
|
||||
|
@ -149,10 +149,7 @@ func (s *Service) UpdateTask(
|
||||
return nil, status.Errorf(codes.Internal, "load job: %v", err)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
actions_service.CreateCommitStatus(ctx, task.Job)
|
||||
|
||||
if req.Msg.State.Result != runnerv1.Result_RESULT_UNSPECIFIED {
|
||||
if err := actions_service.EmitJobsIfReady(task.Job.RunID); err != nil {
|
||||
|
@ -13,6 +13,7 @@ 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"
|
||||
@ -27,6 +28,8 @@ 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,
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 (
|
||||
@ -14,19 +13,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
)
|
||||
|
||||
// ________ _____ .__ __
|
||||
// \______ \ _____/ ____\____ __ __| |_/ |_
|
||||
// | | \_/ __ \ __\\__ \ | | \ |\ __\
|
||||
// | ` \ ___/| | / __ \| | / |_| |
|
||||
// /_______ /\___ >__| (____ /____/|____/__|
|
||||
// \/ \/ \/
|
||||
// __________ .__
|
||||
// \______ \____________ ____ ____ | |__
|
||||
// | | _/\_ __ \__ \ / \_/ ___\| | \
|
||||
// | | \ | | \// __ \| | \ \___| Y \
|
||||
// |______ / |__| (____ /___| /\___ >___| /
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
// SetDefaultBranch updates the default branch
|
||||
func SetDefaultBranch(ctx *gitea_context.PrivateContext) {
|
||||
ownerName := ctx.Params(":owner")
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 (
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 (
|
||||
@ -69,8 +68,8 @@ func (ctx *preReceiveContext) AssertCanWriteCode() bool {
|
||||
if ctx.Written() {
|
||||
return false
|
||||
}
|
||||
ctx.JSON(http.StatusForbidden, map[string]interface{}{
|
||||
"err": "User permission denied for writing.",
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
UserMsg: "User permission denied for writing.",
|
||||
})
|
||||
return false
|
||||
}
|
||||
@ -95,8 +94,8 @@ func (ctx *preReceiveContext) AssertCreatePullRequest() bool {
|
||||
if ctx.Written() {
|
||||
return false
|
||||
}
|
||||
ctx.JSON(http.StatusForbidden, map[string]interface{}{
|
||||
"err": "User permission denied for creating pull-request.",
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
UserMsg: "User permission denied for creating pull-request.",
|
||||
})
|
||||
return false
|
||||
}
|
||||
@ -151,7 +150,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{
|
||||
Err: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName),
|
||||
UserMsg: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -179,7 +178,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{
|
||||
Err: fmt.Sprintf("branch %s is protected from deletion", branchName),
|
||||
UserMsg: fmt.Sprintf("branch %s is protected from deletion", branchName),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -196,7 +195,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{
|
||||
Err: fmt.Sprintf("branch %s is protected from force push", branchName),
|
||||
UserMsg: fmt.Sprintf("branch %s is protected from force push", branchName),
|
||||
})
|
||||
return
|
||||
|
||||
@ -217,7 +216,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{
|
||||
Err: fmt.Sprintf("branch %s is protected from unverified commit %s", branchName, unverifiedCommit),
|
||||
UserMsg: fmt.Sprintf("branch %s is protected from unverified commit %s", branchName, unverifiedCommit),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -272,7 +271,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{
|
||||
Err: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
|
||||
UserMsg: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -297,7 +296,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{
|
||||
Err: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
|
||||
UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -333,7 +332,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{
|
||||
Err: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
|
||||
UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -347,7 +346,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{
|
||||
Err: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
|
||||
UserMsg: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -357,7 +356,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{
|
||||
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()),
|
||||
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()),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -400,7 +399,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{
|
||||
Err: fmt.Sprintf("Tag %s is protected", tagName),
|
||||
UserMsg: fmt.Sprintf("Tag %s is protected", tagName),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -412,15 +411,15 @@ func preReceivePullRequest(ctx *preReceiveContext, oldCommitID, newCommitID, ref
|
||||
}
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.JSON(http.StatusForbidden, map[string]interface{}{
|
||||
"err": "Can't create pull request for an empty repository.",
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
UserMsg: "Can't create pull request for an empty repository.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.opts.IsWiki {
|
||||
ctx.JSON(http.StatusForbidden, map[string]interface{}{
|
||||
"err": "Pull requests are not supported on the wiki.",
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
UserMsg: "Pull requests are not supported on the wiki.",
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -443,7 +442,7 @@ func preReceivePullRequest(ctx *preReceiveContext, oldCommitID, newCommitID, ref
|
||||
|
||||
if !baseBranchExist {
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
Err: fmt.Sprintf("Unexpected ref: %s", refFullName),
|
||||
UserMsg: fmt.Sprintf("Unexpected ref: %s", refFullName),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 (
|
||||
@ -30,8 +29,8 @@ func HookProcReceive(ctx *gitea_context.PrivateContext) {
|
||||
ctx.Error(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err.Error())
|
||||
} else {
|
||||
log.Error(err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
"Err": err.Error(),
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 (
|
||||
@ -16,19 +15,6 @@ 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 {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright 2017 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 contains all internal routes. The package name "internal" isn't usable because Golang reserves it for disabling cross-package usage.
|
||||
package private
|
||||
|
||||
import (
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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,23 +12,10 @@ 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"
|
||||
)
|
||||
|
||||
// __________
|
||||
// \______ \ ____ ______ ____
|
||||
// | _// __ \\____ \ / _ \
|
||||
// | | \ ___/| |_> > <_> )
|
||||
// |____|_ /\___ > __/ \____/
|
||||
// \/ \/|__|
|
||||
// _____ .__ __
|
||||
// / _ \ ______ _____|__| ____ ____ _____ ____ _____/ |_
|
||||
// / /_\ \ / ___// ___/ |/ ___\ / \ / \_/ __ \ / \ __\
|
||||
// / | \\___ \ \___ \| / /_/ > | \ Y Y \ ___/| | \ |
|
||||
// \____|__ /____ >____ >__\___ /|___| /__|_| /\___ >___| /__|
|
||||
// \/ \/ \/ /_____/ \/ \/ \/ \/
|
||||
|
||||
// This file contains common functions relating to setting the Repository for the
|
||||
// internal routes
|
||||
// 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 {
|
||||
@ -45,8 +31,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, map[string]interface{}{
|
||||
"Err": fmt.Sprintf("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),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
@ -71,8 +57,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, map[string]interface{}{
|
||||
"Err": fmt.Sprintf("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),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 (
|
||||
|
@ -31,14 +31,14 @@ func FlushQueues(ctx *context.PrivateContext) {
|
||||
}
|
||||
}()
|
||||
ctx.JSON(http.StatusAccepted, private.Response{
|
||||
Err: "Flushing",
|
||||
UserMsg: "Flushing",
|
||||
})
|
||||
return
|
||||
}
|
||||
err := queue.GetManager().FlushAll(ctx, opts.Timeout)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusRequestTimeout, private.Response{
|
||||
Err: fmt.Sprintf("%v", err),
|
||||
UserMsg: fmt.Sprintf("%v", err),
|
||||
})
|
||||
}
|
||||
ctx.PlainText(http.StatusOK, "success")
|
||||
|
@ -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{
|
||||
Err: "windows servers cannot be gracefully restarted - shutdown and restart manually",
|
||||
UserMsg: "windows servers cannot be gracefully restarted - shutdown and restart manually",
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 (
|
||||
@ -29,7 +28,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
|
||||
keyID := ctx.ParamsInt64(":keyid")
|
||||
if keyID <= 0 {
|
||||
ctx.JSON(http.StatusBadRequest, private.Response{
|
||||
Err: fmt.Sprintf("Bad key id: %d", keyID),
|
||||
UserMsg: fmt.Sprintf("Bad key id: %d", keyID),
|
||||
})
|
||||
}
|
||||
results := private.KeyAndOwner{}
|
||||
@ -38,7 +37,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
|
||||
if err != nil {
|
||||
if asymkey_model.IsErrKeyNotExist(err) {
|
||||
ctx.JSON(http.StatusUnauthorized, private.Response{
|
||||
Err: fmt.Sprintf("Cannot find key: %d", keyID),
|
||||
UserMsg: fmt.Sprintf("Cannot find key: %d", keyID),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -55,7 +54,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.JSON(http.StatusUnauthorized, private.Response{
|
||||
Err: fmt.Sprintf("Cannot find owner with id: %d for key: %d", key.OwnerID, keyID),
|
||||
UserMsg: fmt.Sprintf("Cannot find owner with id: %d for key: %d", key.OwnerID, keyID),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -67,7 +66,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
|
||||
}
|
||||
if !user.IsActive || user.ProhibitLogin {
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
Err: "Your account is disabled.",
|
||||
UserMsg: "Your account is disabled.",
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -113,23 +112,20 @@ 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.ErrServCommand{
|
||||
Results: results,
|
||||
Err: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
|
||||
ctx.JSON(http.StatusNotFound, private.Response{
|
||||
UserMsg: 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.ErrServCommand{
|
||||
Results: results,
|
||||
Err: fmt.Sprintf("Unable to get repository owner: %s/%s %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),
|
||||
})
|
||||
return
|
||||
}
|
||||
if !owner.IsOrganization() && !owner.IsActive {
|
||||
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
|
||||
Results: results,
|
||||
Err: "Repository cannot be accessed, you could retry it later",
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
UserMsg: "Repository cannot be accessed, you could retry it later",
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -144,17 +140,15 @@ 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.ErrServCommand{
|
||||
Results: results,
|
||||
Err: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
|
||||
ctx.JSON(http.StatusNotFound, private.Response{
|
||||
UserMsg: 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.ErrServCommand{
|
||||
Results: results,
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Unable to get repository: %s/%s %v", results.OwnerName, results.RepoName, err),
|
||||
})
|
||||
return
|
||||
@ -167,16 +161,14 @@ func ServCommand(ctx *context.PrivateContext) {
|
||||
results.RepoID = repo.ID
|
||||
|
||||
if repo.IsBeingCreated() {
|
||||
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
|
||||
Results: results,
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: "Repository is being created, you could retry after it finished",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if repo.IsBroken() {
|
||||
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
|
||||
Results: results,
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: "Repository is in a broken state",
|
||||
})
|
||||
return
|
||||
@ -184,9 +176,8 @@ func ServCommand(ctx *context.PrivateContext) {
|
||||
|
||||
// We can shortcut at this point if the repo is a mirror
|
||||
if mode > perm.AccessModeRead && repo.IsMirror {
|
||||
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
|
||||
Results: results,
|
||||
Err: fmt.Sprintf("Mirror Repository %s/%s is read-only", results.OwnerName, results.RepoName),
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
UserMsg: fmt.Sprintf("Mirror Repository %s/%s is read-only", results.OwnerName, results.RepoName),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -196,15 +187,13 @@ func ServCommand(ctx *context.PrivateContext) {
|
||||
key, err := asymkey_model.GetPublicKeyByID(keyID)
|
||||
if err != nil {
|
||||
if asymkey_model.IsErrKeyNotExist(err) {
|
||||
ctx.JSON(http.StatusNotFound, private.ErrServCommand{
|
||||
Results: results,
|
||||
Err: fmt.Sprintf("Cannot find key: %d", keyID),
|
||||
ctx.JSON(http.StatusNotFound, private.Response{
|
||||
UserMsg: 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.ErrServCommand{
|
||||
Results: results,
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Unable to get key: %d Error: %v", keyID, err),
|
||||
})
|
||||
return
|
||||
@ -215,9 +204,8 @@ 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.ErrServCommand{
|
||||
Results: results,
|
||||
Err: fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName),
|
||||
ctx.JSON(http.StatusNotFound, private.Response{
|
||||
UserMsg: fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -232,15 +220,13 @@ 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.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),
|
||||
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),
|
||||
})
|
||||
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.ErrServCommand{
|
||||
Results: results,
|
||||
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),
|
||||
})
|
||||
return
|
||||
@ -262,15 +248,13 @@ 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.ErrServCommand{
|
||||
Results: results,
|
||||
Err: fmt.Sprintf("Public Key: %d:%s owner %d does not exist.", key.ID, key.Name, key.OwnerID),
|
||||
ctx.JSON(http.StatusUnauthorized, private.Response{
|
||||
UserMsg: 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.ErrServCommand{
|
||||
Results: results,
|
||||
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),
|
||||
})
|
||||
return
|
||||
@ -278,7 +262,7 @@ func ServCommand(ctx *context.PrivateContext) {
|
||||
|
||||
if !user.IsActive || user.ProhibitLogin {
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
Err: "Your account is disabled.",
|
||||
UserMsg: "Your account is disabled.",
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -291,9 +275,8 @@ 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.ErrServCommand{
|
||||
Results: results,
|
||||
Err: fmt.Sprintf("Repo: %s/%s is archived.", results.OwnerName, results.RepoName),
|
||||
ctx.JSON(http.StatusUnauthorized, private.Response{
|
||||
UserMsg: fmt.Sprintf("Repo: %s/%s is archived.", results.OwnerName, results.RepoName),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -307,9 +290,8 @@ func ServCommand(ctx *context.PrivateContext) {
|
||||
setting.Service.RequireSignInView) {
|
||||
if key.Type == asymkey_model.KeyTypeDeploy {
|
||||
if deployKey.Mode < mode {
|
||||
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),
|
||||
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),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -322,8 +304,7 @@ 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.ErrServCommand{
|
||||
Results: results,
|
||||
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),
|
||||
})
|
||||
return
|
||||
@ -333,9 +314,8 @@ 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.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),
|
||||
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),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -346,24 +326,21 @@ func ServCommand(ctx *context.PrivateContext) {
|
||||
if !repoExist {
|
||||
owner, err := user_model.GetUserByName(ctx, ownerName)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
|
||||
Results: results,
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Unable to get owner: %s %v", results.OwnerName, err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
|
||||
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
|
||||
Results: results,
|
||||
Err: "Push to create is not enabled for organizations.",
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
UserMsg: "Push to create is not enabled for organizations.",
|
||||
})
|
||||
return
|
||||
}
|
||||
if !owner.IsOrganization() && !setting.Repository.EnablePushCreateUser {
|
||||
ctx.JSON(http.StatusForbidden, private.ErrServCommand{
|
||||
Results: results,
|
||||
Err: "Push to create is not enabled for users.",
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
UserMsg: "Push to create is not enabled for users.",
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -371,9 +348,8 @@ 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.ErrServCommand{
|
||||
Results: results,
|
||||
Err: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
|
||||
ctx.JSON(http.StatusNotFound, private.Response{
|
||||
UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -384,15 +360,13 @@ 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.ErrServCommand{
|
||||
Results: results,
|
||||
Err: "repository wiki is disabled",
|
||||
ctx.JSON(http.StatusForbidden, private.Response{
|
||||
UserMsg: "repository wiki is disabled",
|
||||
})
|
||||
return
|
||||
}
|
||||
log.Error("Failed to get the wiki unit in %-v Error: %v", repo, err)
|
||||
ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
|
||||
Results: results,
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Failed to get the wiki unit in %s/%s Error: %v", ownerName, repoName, err),
|
||||
})
|
||||
return
|
||||
@ -401,8 +375,7 @@ 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.ErrServCommand{
|
||||
Results: results,
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Failed to initialize the wiki in %s/%s Error: %v", ownerName, repoName, err),
|
||||
})
|
||||
return
|
||||
|
@ -4,6 +4,7 @@
|
||||
package explore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
@ -18,7 +19,7 @@ import (
|
||||
const (
|
||||
// tplExploreRepos explore repositories page template
|
||||
tplExploreRepos base.TplName = "explore/repos"
|
||||
relevantReposOnlyParam string = "no_filter"
|
||||
relevantReposOnlyParam string = "only_show_relevant"
|
||||
)
|
||||
|
||||
// RepoSearchOptions when calling search repositories
|
||||
@ -137,7 +138,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParam(ctx, "topic", "TopicOnly")
|
||||
pager.AddParam(ctx, "language", "Language")
|
||||
pager.AddParamString(relevantReposOnlyParam, ctx.FormString(relevantReposOnlyParam))
|
||||
pager.AddParamString(relevantReposOnlyParam, fmt.Sprint(opts.OnlyShowRelevant))
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, opts.TplName)
|
||||
@ -156,11 +157,18 @@ 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: !ctx.FormBool(relevantReposOnlyParam),
|
||||
OnlyShowRelevant: onlyShowRelevant,
|
||||
})
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ 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"
|
||||
@ -264,10 +263,7 @@ func Rerun(ctx *context_module.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := actions_service.CreateCommitStatus(ctx, job); err != nil {
|
||||
log.Error("Update commit status for job %v failed: %v", job.ID, err)
|
||||
// go on
|
||||
}
|
||||
actions_service.CreateCommitStatus(ctx, job)
|
||||
|
||||
ctx.JSON(http.StatusOK, struct{}{})
|
||||
}
|
||||
@ -308,12 +304,7 @@ func Cancel(ctx *context_module.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
actions_service.CreateCommitStatus(ctx, jobs...)
|
||||
|
||||
ctx.JSON(http.StatusOK, struct{}{})
|
||||
}
|
||||
@ -349,6 +340,8 @@ func Approve(ctx *context_module.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
actions_service.CreateCommitStatus(ctx, jobs...)
|
||||
|
||||
ctx.JSON(http.StatusOK, struct{}{})
|
||||
}
|
||||
|
||||
|
@ -64,12 +64,7 @@ func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
CreateCommitStatus(ctx, jobs...)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -96,10 +91,7 @@ func CancelAbandonedJobs(ctx context.Context) error {
|
||||
log.Warn("cancel abandoned job %v: %v", job.ID, err)
|
||||
// go on
|
||||
}
|
||||
if err := CreateCommitStatus(ctx, job); err != nil {
|
||||
log.Error("Update commit status for job %v failed: %v", job.ID, err)
|
||||
// go on
|
||||
}
|
||||
CreateCommitStatus(ctx, job)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -6,79 +6,80 @@ 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"
|
||||
)
|
||||
|
||||
func CreateCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) error {
|
||||
// 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 {
|
||||
if err := job.LoadAttributes(ctx); err != nil {
|
||||
return fmt.Errorf("load run: %w", err)
|
||||
}
|
||||
|
||||
run := job.Run
|
||||
|
||||
var (
|
||||
sha string
|
||||
creatorID int64
|
||||
event string
|
||||
)
|
||||
|
||||
switch run.Event {
|
||||
case webhook_module.HookEventPush:
|
||||
event = "push"
|
||||
payload, err := run.GetPushEventPayload()
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetPushEventPayload: %w", err)
|
||||
}
|
||||
|
||||
// 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:
|
||||
if 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)
|
||||
}
|
||||
|
||||
switch {
|
||||
case payload.PullRequest == nil:
|
||||
if payload.PullRequest == nil {
|
||||
return fmt.Errorf("pull request is missing in event payload")
|
||||
case payload.PullRequest.Head == nil:
|
||||
} else if 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
|
||||
ctxname := job.Name
|
||||
state := toCommitStatus(job.Status)
|
||||
creator, err := user_model.GetUserByID(ctx, creatorID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserByID: %w", err)
|
||||
// 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)
|
||||
state := toCommitStatus(job.Status)
|
||||
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
|
||||
@ -88,6 +89,26 @@ 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,
|
||||
@ -95,9 +116,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: creatorID,
|
||||
CreatorID: creator.ID,
|
||||
State: state,
|
||||
},
|
||||
}); err != nil {
|
||||
@ -109,9 +130,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:
|
||||
case actions_model.StatusSuccess, actions_model.StatusSkipped:
|
||||
return api.CommitStatusSuccess
|
||||
case actions_model.StatusFailure, actions_model.StatusCancelled, actions_model.StatusSkipped:
|
||||
case actions_model.StatusFailure, actions_model.StatusCancelled:
|
||||
return api.CommitStatusFailure
|
||||
case actions_model.StatusWaiting, actions_model.StatusBlocked:
|
||||
return api.CommitStatusPending
|
||||
|
@ -45,11 +45,11 @@ func jobEmitterQueueHandle(data ...queue.Data) []queue.Data {
|
||||
}
|
||||
|
||||
func checkJobsOfRun(ctx context.Context, runID int64) 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
|
||||
}
|
||||
if err := db.WithTx(ctx, func(ctx context.Context) error {
|
||||
idToJobs := make(map[string][]*actions_model.ActionRunJob, len(jobs))
|
||||
for _, job := range jobs {
|
||||
idToJobs[job.JobID] = append(idToJobs[job.JobID], job)
|
||||
@ -67,7 +67,11 @@ func checkJobsOfRun(ctx context.Context, runID int64) error {
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
CreateCommitStatus(ctx, jobs...)
|
||||
return nil
|
||||
}
|
||||
|
||||
type jobStatusResolver struct {
|
||||
|
@ -185,12 +185,7 @@ 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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
CreateCommitStatus(ctx, jobs...)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ func (source *Source) listLdapGroupMemberships(l *ldap.Conn, uid string, applyGr
|
||||
}
|
||||
|
||||
var searchFilter string
|
||||
if applyGroupFilter {
|
||||
if applyGroupFilter && groupFilter != "" {
|
||||
searchFilter = fmt.Sprintf("(&(%s)(%s=%s))", groupFilter, source.GroupMemberUID, ldap.EscapeFilter(uid))
|
||||
} else {
|
||||
searchFilter = fmt.Sprintf("(%s=%s)", source.GroupMemberUID, ldap.EscapeFilter(uid))
|
||||
|
@ -26,12 +26,15 @@
|
||||
<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 .OnlyShowRelevant}}
|
||||
{{if and .PageIsExploreRepositories .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 "?no_filter=1")|Escape) | Safe}}</span>
|
||||
<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>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="ui divider"></div>
|
||||
|
@ -43,8 +43,8 @@ func TestAPIPrivateServ(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
// Can push to a repo we own
|
||||
results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
results, extra := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, extra.Error)
|
||||
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, err = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
results, extra = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, extra.Error)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Cannot pull from a private repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
results, extra = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.Error(t, extra.Error)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Can pull from a public repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
results, extra = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, extra.Error)
|
||||
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, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
results, extra = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, extra.Error)
|
||||
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, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, extra.Error)
|
||||
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, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, extra.Error)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Cannot pull from a private repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
results, extra = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.Error(t, extra.Error)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Cannot pull from a public repo we're not associated with
|
||||
results, err = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
results, extra = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.Error(t, extra.Error)
|
||||
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, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, err)
|
||||
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.Error(t, extra.Error)
|
||||
assert.Empty(t, results)
|
||||
|
||||
// Can pull from repo we're a writing deploy key for
|
||||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, extra.Error)
|
||||
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, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, extra.Error)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
|
Loading…
x
Reference in New Issue
Block a user