Make hook status printing configurable with delay (#9641)
* Delay printing hook statuses until after 1 second * Move to a 5s delay, wrapped writer structure and add config * Update cmd/hook.go * Apply suggestions from code review * Update cmd/hook.go Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
This commit is contained in:
parent
83f9359a75
commit
65baacf227
3 changed files with 128 additions and 26 deletions
148
cmd/hook.go
148
cmd/hook.go
|
@ -8,10 +8,12 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -58,6 +60,85 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type delayWriter struct {
|
||||||
|
internal io.Writer
|
||||||
|
buf *bytes.Buffer
|
||||||
|
timer *time.Timer
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDelayWriter(internal io.Writer, delay time.Duration) *delayWriter {
|
||||||
|
timer := time.NewTimer(delay)
|
||||||
|
return &delayWriter{
|
||||||
|
internal: internal,
|
||||||
|
buf: &bytes.Buffer{},
|
||||||
|
timer: timer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *delayWriter) Write(p []byte) (n int, err error) {
|
||||||
|
if d.buf != nil {
|
||||||
|
select {
|
||||||
|
case <-d.timer.C:
|
||||||
|
_, err := d.internal.Write(d.buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
d.buf = nil
|
||||||
|
return d.internal.Write(p)
|
||||||
|
default:
|
||||||
|
return d.buf.Write(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d.internal.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *delayWriter) WriteString(s string) (n int, err error) {
|
||||||
|
if d.buf != nil {
|
||||||
|
select {
|
||||||
|
case <-d.timer.C:
|
||||||
|
_, err := d.internal.Write(d.buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
d.buf = nil
|
||||||
|
return d.internal.Write([]byte(s))
|
||||||
|
default:
|
||||||
|
return d.buf.WriteString(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d.internal.Write([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *delayWriter) Close() error {
|
||||||
|
if d == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
stopped := d.timer.Stop()
|
||||||
|
if stopped {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-d.timer.C:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if d.buf == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := d.internal.Write(d.buf.Bytes())
|
||||||
|
d.buf = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type nilWriter struct{}
|
||||||
|
|
||||||
|
func (n *nilWriter) Write(p []byte) (int, error) {
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *nilWriter) WriteString(s string) (int, error) {
|
||||||
|
return len(s), nil
|
||||||
|
}
|
||||||
|
|
||||||
func runHookPreReceive(c *cli.Context) error {
|
func runHookPreReceive(c *cli.Context) error {
|
||||||
if os.Getenv(models.EnvIsInternal) == "true" {
|
if os.Getenv(models.EnvIsInternal) == "true" {
|
||||||
return nil
|
return nil
|
||||||
|
@ -101,6 +182,18 @@ Gitea or set your environment appropriately.`, "")
|
||||||
total := 0
|
total := 0
|
||||||
lastline := 0
|
lastline := 0
|
||||||
|
|
||||||
|
var out io.Writer
|
||||||
|
out = &nilWriter{}
|
||||||
|
if setting.Git.VerbosePush {
|
||||||
|
if setting.Git.VerbosePushDelay > 0 {
|
||||||
|
dWriter := newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay)
|
||||||
|
defer dWriter.Close()
|
||||||
|
out = dWriter
|
||||||
|
} else {
|
||||||
|
out = os.Stdout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
// TODO: support news feeds for wiki
|
// TODO: support news feeds for wiki
|
||||||
if isWiki {
|
if isWiki {
|
||||||
|
@ -124,12 +217,10 @@ Gitea or set your environment appropriately.`, "")
|
||||||
newCommitIDs[count] = newCommitID
|
newCommitIDs[count] = newCommitID
|
||||||
refFullNames[count] = refFullName
|
refFullNames[count] = refFullName
|
||||||
count++
|
count++
|
||||||
fmt.Fprintf(os.Stdout, "*")
|
fmt.Fprintf(out, "*")
|
||||||
os.Stdout.Sync()
|
|
||||||
|
|
||||||
if count >= hookBatchSize {
|
if count >= hookBatchSize {
|
||||||
fmt.Fprintf(os.Stdout, " Checking %d branches\n", count)
|
fmt.Fprintf(out, " Checking %d branches\n", count)
|
||||||
os.Stdout.Sync()
|
|
||||||
|
|
||||||
hookOptions.OldCommitIDs = oldCommitIDs
|
hookOptions.OldCommitIDs = oldCommitIDs
|
||||||
hookOptions.NewCommitIDs = newCommitIDs
|
hookOptions.NewCommitIDs = newCommitIDs
|
||||||
|
@ -147,12 +238,10 @@ Gitea or set your environment appropriately.`, "")
|
||||||
lastline = 0
|
lastline = 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stdout, ".")
|
fmt.Fprintf(out, ".")
|
||||||
os.Stdout.Sync()
|
|
||||||
}
|
}
|
||||||
if lastline >= hookBatchSize {
|
if lastline >= hookBatchSize {
|
||||||
fmt.Fprintf(os.Stdout, "\n")
|
fmt.Fprintf(out, "\n")
|
||||||
os.Stdout.Sync()
|
|
||||||
lastline = 0
|
lastline = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,8 +251,7 @@ Gitea or set your environment appropriately.`, "")
|
||||||
hookOptions.NewCommitIDs = newCommitIDs[:count]
|
hookOptions.NewCommitIDs = newCommitIDs[:count]
|
||||||
hookOptions.RefFullNames = refFullNames[:count]
|
hookOptions.RefFullNames = refFullNames[:count]
|
||||||
|
|
||||||
fmt.Fprintf(os.Stdout, " Checking %d branches\n", count)
|
fmt.Fprintf(out, " Checking %d branches\n", count)
|
||||||
os.Stdout.Sync()
|
|
||||||
|
|
||||||
statusCode, msg := private.HookPreReceive(username, reponame, hookOptions)
|
statusCode, msg := private.HookPreReceive(username, reponame, hookOptions)
|
||||||
switch statusCode {
|
switch statusCode {
|
||||||
|
@ -173,14 +261,11 @@ Gitea or set your environment appropriately.`, "")
|
||||||
fail(msg, "")
|
fail(msg, "")
|
||||||
}
|
}
|
||||||
} else if lastline > 0 {
|
} else if lastline > 0 {
|
||||||
fmt.Fprintf(os.Stdout, "\n")
|
fmt.Fprintf(out, "\n")
|
||||||
os.Stdout.Sync()
|
|
||||||
lastline = 0
|
lastline = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(os.Stdout, "Checked %d references in total\n", total)
|
fmt.Fprintf(out, "Checked %d references in total\n", total)
|
||||||
os.Stdout.Sync()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +291,19 @@ Gitea or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var out io.Writer
|
||||||
|
var dWriter *delayWriter
|
||||||
|
out = &nilWriter{}
|
||||||
|
if setting.Git.VerbosePush {
|
||||||
|
if setting.Git.VerbosePushDelay > 0 {
|
||||||
|
dWriter = newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay)
|
||||||
|
defer dWriter.Close()
|
||||||
|
out = dWriter
|
||||||
|
} else {
|
||||||
|
out = os.Stdout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the environment setted on serv command
|
// the environment setted on serv command
|
||||||
repoUser := os.Getenv(models.EnvRepoUsername)
|
repoUser := os.Getenv(models.EnvRepoUsername)
|
||||||
isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
|
isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
|
||||||
|
@ -241,7 +339,7 @@ Gitea or set your environment appropriately.`, "")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(os.Stdout, ".")
|
fmt.Fprintf(out, ".")
|
||||||
oldCommitIDs[count] = string(fields[0])
|
oldCommitIDs[count] = string(fields[0])
|
||||||
newCommitIDs[count] = string(fields[1])
|
newCommitIDs[count] = string(fields[1])
|
||||||
refFullNames[count] = string(fields[2])
|
refFullNames[count] = string(fields[2])
|
||||||
|
@ -250,16 +348,15 @@ Gitea or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
total++
|
total++
|
||||||
os.Stdout.Sync()
|
|
||||||
|
|
||||||
if count >= hookBatchSize {
|
if count >= hookBatchSize {
|
||||||
fmt.Fprintf(os.Stdout, " Processing %d references\n", count)
|
fmt.Fprintf(out, " Processing %d references\n", count)
|
||||||
os.Stdout.Sync()
|
|
||||||
hookOptions.OldCommitIDs = oldCommitIDs
|
hookOptions.OldCommitIDs = oldCommitIDs
|
||||||
hookOptions.NewCommitIDs = newCommitIDs
|
hookOptions.NewCommitIDs = newCommitIDs
|
||||||
hookOptions.RefFullNames = refFullNames
|
hookOptions.RefFullNames = refFullNames
|
||||||
resp, err := private.HookPostReceive(repoUser, repoName, hookOptions)
|
resp, err := private.HookPostReceive(repoUser, repoName, hookOptions)
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
|
_ = dWriter.Close()
|
||||||
hookPrintResults(results)
|
hookPrintResults(results)
|
||||||
fail("Internal Server Error", err)
|
fail("Internal Server Error", err)
|
||||||
}
|
}
|
||||||
|
@ -277,9 +374,9 @@ Gitea or set your environment appropriately.`, "")
|
||||||
fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
|
fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stdout, "Processed %d references in total\n", total)
|
fmt.Fprintf(out, "Processed %d references in total\n", total)
|
||||||
os.Stdout.Sync()
|
|
||||||
|
|
||||||
|
_ = dWriter.Close()
|
||||||
hookPrintResults(results)
|
hookPrintResults(results)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -288,19 +385,18 @@ Gitea or set your environment appropriately.`, "")
|
||||||
hookOptions.NewCommitIDs = newCommitIDs[:count]
|
hookOptions.NewCommitIDs = newCommitIDs[:count]
|
||||||
hookOptions.RefFullNames = refFullNames[:count]
|
hookOptions.RefFullNames = refFullNames[:count]
|
||||||
|
|
||||||
fmt.Fprintf(os.Stdout, " Processing %d references\n", count)
|
fmt.Fprintf(out, " Processing %d references\n", count)
|
||||||
os.Stdout.Sync()
|
|
||||||
|
|
||||||
resp, err := private.HookPostReceive(repoUser, repoName, hookOptions)
|
resp, err := private.HookPostReceive(repoUser, repoName, hookOptions)
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
|
_ = dWriter.Close()
|
||||||
hookPrintResults(results)
|
hookPrintResults(results)
|
||||||
fail("Internal Server Error", err)
|
fail("Internal Server Error", err)
|
||||||
}
|
}
|
||||||
wasEmpty = wasEmpty || resp.RepoWasEmpty
|
wasEmpty = wasEmpty || resp.RepoWasEmpty
|
||||||
results = append(results, resp.Results...)
|
results = append(results, resp.Results...)
|
||||||
|
|
||||||
fmt.Fprintf(os.Stdout, "Processed %d references in total\n", total)
|
fmt.Fprintf(out, "Processed %d references in total\n", total)
|
||||||
os.Stdout.Sync()
|
|
||||||
|
|
||||||
if wasEmpty && masterPushed {
|
if wasEmpty && masterPushed {
|
||||||
// We need to tell the repo to reset the default branch to master
|
// We need to tell the repo to reset the default branch to master
|
||||||
|
@ -309,7 +405,7 @@ Gitea or set your environment appropriately.`, "")
|
||||||
fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
|
fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ = dWriter.Close()
|
||||||
hookPrintResults(results)
|
hookPrintResults(results)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -522,6 +522,8 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false`
|
||||||
- `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view.
|
- `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view.
|
||||||
- `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/
|
- `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/
|
||||||
- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1
|
- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1
|
||||||
|
- `VERBOSE_PUSH`: **true**: Print status information about pushes as they are being processed.
|
||||||
|
- `VERBOSE_PUSH_DELAY`: **5s**: Only print verbose information if push takes longer than this delay.
|
||||||
|
|
||||||
## Git - Timeout settings (`git.timeout`)
|
## Git - Timeout settings (`git.timeout`)
|
||||||
- `DEFAUlT`: **360**: Git operations default timeout seconds.
|
- `DEFAUlT`: **360**: Git operations default timeout seconds.
|
||||||
|
|
|
@ -21,6 +21,8 @@ var (
|
||||||
MaxGitDiffLines int
|
MaxGitDiffLines int
|
||||||
MaxGitDiffLineCharacters int
|
MaxGitDiffLineCharacters int
|
||||||
MaxGitDiffFiles int
|
MaxGitDiffFiles int
|
||||||
|
VerbosePush bool
|
||||||
|
VerbosePushDelay time.Duration
|
||||||
GCArgs []string `ini:"GC_ARGS" delim:" "`
|
GCArgs []string `ini:"GC_ARGS" delim:" "`
|
||||||
EnableAutoGitWireProtocol bool
|
EnableAutoGitWireProtocol bool
|
||||||
Timeout struct {
|
Timeout struct {
|
||||||
|
@ -36,6 +38,8 @@ var (
|
||||||
MaxGitDiffLines: 1000,
|
MaxGitDiffLines: 1000,
|
||||||
MaxGitDiffLineCharacters: 5000,
|
MaxGitDiffLineCharacters: 5000,
|
||||||
MaxGitDiffFiles: 100,
|
MaxGitDiffFiles: 100,
|
||||||
|
VerbosePush: true,
|
||||||
|
VerbosePushDelay: 5 * time.Second,
|
||||||
GCArgs: []string{},
|
GCArgs: []string{},
|
||||||
EnableAutoGitWireProtocol: true,
|
EnableAutoGitWireProtocol: true,
|
||||||
Timeout: struct {
|
Timeout: struct {
|
||||||
|
|
Reference in a new issue