mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-22 16:36:30 +00:00
Drop error only on purpose or else report back or log (#514)
- Remove Deadcode - Simplify Code - Drop error only on purpose
This commit is contained in:
parent
f454371e56
commit
fe31fb1e06
59 changed files with 464 additions and 347 deletions
|
@ -8,7 +8,17 @@ linters:
|
||||||
- gofmt
|
- gofmt
|
||||||
- goimports
|
- goimports
|
||||||
- govet
|
- govet
|
||||||
|
- deadcode
|
||||||
|
- gosimple
|
||||||
|
- typecheck
|
||||||
|
- errcheck
|
||||||
- bidichk
|
- bidichk
|
||||||
|
|
||||||
run:
|
run:
|
||||||
timeout: 5m
|
timeout: 5m
|
||||||
|
|
||||||
|
issues:
|
||||||
|
exclude-rules:
|
||||||
|
- path: woodpecker-go/woodpecker/client.go|server/swagger/swagger.go
|
||||||
|
linters:
|
||||||
|
- deadcode
|
||||||
|
|
|
@ -122,7 +122,9 @@ func (r *Runner) Run(ctx context.Context) error {
|
||||||
case <-time.After(time.Minute):
|
case <-time.After(time.Minute):
|
||||||
logger.Debug().Msg("pipeline lease renewed")
|
logger.Debug().Msg("pipeline lease renewed")
|
||||||
|
|
||||||
r.client.Extend(ctx, work.ID)
|
if err := r.client.Extend(ctx, work.ID); err != nil {
|
||||||
|
log.Error().Err(err).Msg("extending pipeline deadline failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -159,12 +161,14 @@ func (r *Runner) Run(ctx context.Context) error {
|
||||||
loglogger.Debug().Msg("log stream opened")
|
loglogger.Debug().Msg("log stream opened")
|
||||||
|
|
||||||
limitedPart := io.LimitReader(part, maxLogsUpload)
|
limitedPart := io.LimitReader(part, maxLogsUpload)
|
||||||
logstream := rpc.NewLineWriter(r.client, work.ID, proc.Alias, secrets...)
|
logStream := rpc.NewLineWriter(r.client, work.ID, proc.Alias, secrets...)
|
||||||
io.Copy(logstream, limitedPart)
|
if _, err := io.Copy(logStream, limitedPart); err != nil {
|
||||||
|
log.Error().Err(err).Msg("copy limited logStream part")
|
||||||
|
}
|
||||||
|
|
||||||
loglogger.Debug().Msg("log stream copied")
|
loglogger.Debug().Msg("log stream copied")
|
||||||
|
|
||||||
data, err := json.Marshal(logstream.Lines())
|
data, err := json.Marshal(logStream.Lines())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loglogger.Err(err).Msg("could not marshal logstream")
|
loglogger.Err(err).Msg("could not marshal logstream")
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,9 @@ func buildList(c *cli.Context) error {
|
||||||
if status != "" && build.Status != status {
|
if status != "" && build.Status != status {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tmpl.Execute(os.Stdout, build)
|
if err := tmpl.Execute(os.Stdout, build); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -44,7 +44,9 @@ func buildQueue(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, build := range builds {
|
for _, build := range builds {
|
||||||
tmpl.Execute(os.Stdout, build)
|
if err := tmpl.Execute(os.Stdout, build); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,8 +260,7 @@ var defaultLogger = pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reade
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logstream := NewLineWriter(proc.Alias)
|
logStream := NewLineWriter(proc.Alias)
|
||||||
io.Copy(logstream, part)
|
_, err = io.Copy(logStream, part)
|
||||||
|
return err
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -43,7 +43,7 @@ func lint(c *cli.Context) error {
|
||||||
// check if it is a regular file (not dir)
|
// check if it is a regular file (not dir)
|
||||||
if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".yml") {
|
if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".yml") {
|
||||||
fmt.Println("#", info.Name())
|
fmt.Println("#", info.Name())
|
||||||
lintFile(path)
|
_ = lintFile(path) // TODO: should we drop errors or store them and report back?
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,9 @@ func registryList(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, registry := range list {
|
for _, registry := range list {
|
||||||
tmpl.Execute(os.Stdout, registry)
|
if err := tmpl.Execute(os.Stdout, registry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,9 @@ func repoList(c *cli.Context) error {
|
||||||
if org != "" && org != repo.Owner {
|
if org != "" && org != repo.Owner {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tmpl.Execute(os.Stdout, repo)
|
if err := tmpl.Execute(os.Stdout, repo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,9 @@ func repoSync(c *cli.Context) error {
|
||||||
if org != "" && org != repo.Owner {
|
if org != "" && org != repo.Owner {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tmpl.Execute(os.Stdout, repo)
|
if err := tmpl.Execute(os.Stdout, repo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,9 @@ func secretList(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, registry := range list {
|
for _, registry := range list {
|
||||||
tmpl.Execute(os.Stdout, registry)
|
if err := tmpl.Execute(os.Stdout, registry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,9 @@ func userList(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
tmpl.Execute(os.Stdout, user)
|
if err := tmpl.Execute(os.Stdout, user); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/agent"
|
"github.com/woodpecker-ci/woodpecker/agent"
|
||||||
|
@ -46,7 +47,7 @@ func handleHeartbeat(w http.ResponseWriter, r *http.Request) {
|
||||||
func handleVersion(w http.ResponseWriter, r *http.Request) {
|
func handleVersion(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
w.Header().Add("Content-Type", "text/json")
|
w.Header().Add("Content-Type", "text/json")
|
||||||
json.NewEncoder(w).Encode(versionResp{
|
_ = json.NewEncoder(w).Encode(versionResp{
|
||||||
Source: "https://github.com/woodpecker-ci/woodpecker",
|
Source: "https://github.com/woodpecker-ci/woodpecker",
|
||||||
Version: version.String(),
|
Version: version.String(),
|
||||||
})
|
})
|
||||||
|
@ -59,7 +60,9 @@ func handleStats(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
}
|
}
|
||||||
w.Header().Add("Content-Type", "text/json")
|
w.Header().Add("Content-Type", "text/json")
|
||||||
counter.WriteTo(w)
|
if _, err := counter.WriteTo(w); err != nil {
|
||||||
|
log.Error().Err(err).Msg("handleStats")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type versionResp struct {
|
type versionResp struct {
|
||||||
|
|
|
@ -12,14 +12,6 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WithContext returns a copy of parent context whose Done channel is closed
|
|
||||||
// when an os interrupt signal is received.
|
|
||||||
func WithContext(ctx context.Context) context.Context {
|
|
||||||
return WithContextFunc(ctx, func() {
|
|
||||||
println("interrupt received, terminating process")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithContextFunc returns a copy of parent context that is cancelled when
|
// WithContextFunc returns a copy of parent context that is cancelled when
|
||||||
// an os interrupt signal is received. The callback function f is invoked
|
// an os interrupt signal is received. The callback function f is invoked
|
||||||
// before cancellation.
|
// before cancellation.
|
||||||
|
|
|
@ -19,19 +19,21 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
_ "github.com/joho/godotenv/autoload"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/version"
|
"github.com/woodpecker-ci/woodpecker/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
godotenv.Load(".env")
|
if err := godotenv.Load(".env"); err != nil {
|
||||||
|
log.Error().Err(err).Msg("load godotenv failed")
|
||||||
|
}
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "woodpecker-server"
|
app.Name = "woodpecker-server"
|
||||||
app.Version = version.String()
|
app.Version = version.String()
|
||||||
app.Usage = "woodpecker server"
|
app.Usage = "woodpecker server"
|
||||||
app.Action = loop
|
app.Action = run
|
||||||
app.Flags = flags
|
app.Flags = flags
|
||||||
app.Before = before
|
app.Before = before
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func loop(c *cli.Context) error {
|
func run(c *cli.Context) error {
|
||||||
|
|
||||||
if c.Bool("pretty") {
|
if c.Bool("pretty") {
|
||||||
log.Logger = log.Output(
|
log.Logger = log.Output(
|
||||||
|
@ -224,7 +224,9 @@ func loop(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := cacheDir()
|
dir := cacheDir()
|
||||||
os.MkdirAll(dir, 0700)
|
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
manager := &autocert.Manager{
|
manager := &autocert.Manager{
|
||||||
Prompt: autocert.AcceptTOS,
|
Prompt: autocert.AcceptTOS,
|
||||||
|
@ -259,7 +261,9 @@ func setupEvilGlobals(c *cli.Context, v store.Store, r remote.Remote) {
|
||||||
server.Config.Services.Queue = setupQueue(c, v)
|
server.Config.Services.Queue = setupQueue(c, v)
|
||||||
server.Config.Services.Logs = logging.New()
|
server.Config.Services.Logs = logging.New()
|
||||||
server.Config.Services.Pubsub = pubsub.New()
|
server.Config.Services.Pubsub = pubsub.New()
|
||||||
server.Config.Services.Pubsub.Create(context.Background(), "topic/events")
|
if err := server.Config.Services.Pubsub.Create(context.Background(), "topic/events"); err != nil {
|
||||||
|
log.Error().Err(err).Msg("could not create pubsub service")
|
||||||
|
}
|
||||||
server.Config.Services.Registries = setupRegistryService(c, v)
|
server.Config.Services.Registries = setupRegistryService(c, v)
|
||||||
server.Config.Services.Secrets = setupSecretService(c, v)
|
server.Config.Services.Secrets = setupSecretService(c, v)
|
||||||
server.Config.Services.Senders = sender.New(v, v)
|
server.Config.Services.Senders = sender.New(v, v)
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -35,6 +35,7 @@ require (
|
||||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
|
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450
|
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang v1.11.0
|
||||||
github.com/rs/zerolog v1.25.0
|
github.com/rs/zerolog v1.25.0
|
||||||
github.com/stretchr/objx v0.3.0 // indirect
|
github.com/stretchr/objx v0.3.0 // indirect
|
||||||
|
|
|
@ -79,7 +79,7 @@ func toHostConfig(proc *backend.Step) *container.HostConfig {
|
||||||
}
|
}
|
||||||
config.Tmpfs = map[string]string{}
|
config.Tmpfs = map[string]string{}
|
||||||
for _, path := range proc.Tmpfs {
|
for _, path := range proc.Tmpfs {
|
||||||
if strings.Index(path, ":") == -1 {
|
if !strings.Contains(path, ":") {
|
||||||
config.Tmpfs[path] = ""
|
config.Tmpfs[path] = ""
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -89,9 +89,6 @@ func toHostConfig(proc *backend.Step) *container.HostConfig {
|
||||||
}
|
}
|
||||||
config.Tmpfs[parts[0]] = parts[1]
|
config.Tmpfs[parts[0]] = parts[1]
|
||||||
}
|
}
|
||||||
// if proc.OomKillDisable {
|
|
||||||
// config.OomKillDisable = &proc.OomKillDisable
|
|
||||||
// }
|
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/moby/moby/pkg/jsonmessage"
|
"github.com/moby/moby/pkg/jsonmessage"
|
||||||
"github.com/moby/moby/pkg/stdcopy"
|
"github.com/moby/moby/pkg/stdcopy"
|
||||||
"github.com/moby/term"
|
"github.com/moby/term"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/pipeline/backend"
|
"github.com/woodpecker-ci/woodpecker/pipeline/backend"
|
||||||
)
|
)
|
||||||
|
@ -80,7 +81,9 @@ func (e *engine) Exec(ctx context.Context, proc *backend.Step) error {
|
||||||
defer responseBody.Close()
|
defer responseBody.Close()
|
||||||
|
|
||||||
fd, isTerminal := term.GetFdInfo(os.Stdout)
|
fd, isTerminal := term.GetFdInfo(os.Stdout)
|
||||||
jsonmessage.DisplayJSONMessagesStream(responseBody, os.Stdout, fd, isTerminal, nil)
|
if err := jsonmessage.DisplayJSONMessagesStream(responseBody, os.Stdout, fd, isTerminal, nil); err != nil {
|
||||||
|
log.Error().Err(err).Msg("DisplayJSONMessagesStream")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// fix for drone/drone#1917
|
// fix for drone/drone#1917
|
||||||
if perr != nil && proc.AuthConfig.Password != "" {
|
if perr != nil && proc.AuthConfig.Password != "" {
|
||||||
|
@ -98,7 +101,9 @@ func (e *engine) Exec(ctx context.Context, proc *backend.Step) error {
|
||||||
}
|
}
|
||||||
defer responseBody.Close()
|
defer responseBody.Close()
|
||||||
fd, isTerminal := term.GetFdInfo(os.Stdout)
|
fd, isTerminal := term.GetFdInfo(os.Stdout)
|
||||||
jsonmessage.DisplayJSONMessagesStream(responseBody, os.Stdout, fd, isTerminal, nil)
|
if err := jsonmessage.DisplayJSONMessagesStream(responseBody, os.Stdout, fd, isTerminal, nil); err != nil {
|
||||||
|
log.Error().Err(err).Msg("DisplayJSONMessagesStream")
|
||||||
|
}
|
||||||
|
|
||||||
_, err = e.client.ContainerCreate(ctx, config, hostConfig, nil, nil, proc.Name)
|
_, err = e.client.ContainerCreate(ctx, config, hostConfig, nil, nil, proc.Name)
|
||||||
}
|
}
|
||||||
|
@ -162,11 +167,12 @@ func (e *engine) Tail(ctx context.Context, proc *backend.Step) (io.ReadCloser, e
|
||||||
}
|
}
|
||||||
rc, wc := io.Pipe()
|
rc, wc := io.Pipe()
|
||||||
|
|
||||||
|
// de multiplex 'logs' who contains two streams, previously multiplexed together using StdWriter
|
||||||
go func() {
|
go func() {
|
||||||
stdcopy.StdCopy(wc, wc, logs)
|
_, _ = stdcopy.StdCopy(wc, wc, logs)
|
||||||
logs.Close()
|
_ = logs.Close()
|
||||||
wc.Close()
|
_ = wc.Close()
|
||||||
rc.Close()
|
_ = rc.Close()
|
||||||
}()
|
}()
|
||||||
return rc, nil
|
return rc, nil
|
||||||
}
|
}
|
||||||
|
@ -174,15 +180,23 @@ func (e *engine) Tail(ctx context.Context, proc *backend.Step) (io.ReadCloser, e
|
||||||
func (e *engine) Destroy(_ context.Context, conf *backend.Config) error {
|
func (e *engine) Destroy(_ context.Context, conf *backend.Config) error {
|
||||||
for _, stage := range conf.Stages {
|
for _, stage := range conf.Stages {
|
||||||
for _, step := range stage.Steps {
|
for _, step := range stage.Steps {
|
||||||
e.client.ContainerKill(noContext, step.Name, "9")
|
if err := e.client.ContainerKill(noContext, step.Name, "9"); err != nil {
|
||||||
e.client.ContainerRemove(noContext, step.Name, removeOpts)
|
log.Error().Err(err).Msgf("could not kill container '%s'", stage.Name)
|
||||||
|
}
|
||||||
|
if err := e.client.ContainerRemove(noContext, step.Name, removeOpts); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("could not remove container '%s'", stage.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, v := range conf.Volumes {
|
for _, v := range conf.Volumes {
|
||||||
e.client.VolumeRemove(noContext, v.Name, true)
|
if err := e.client.VolumeRemove(noContext, v.Name, true); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("could not remove volume '%s'", v.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, n := range conf.Networks {
|
for _, n := range conf.Networks {
|
||||||
e.client.NetworkRemove(noContext, n.Name)
|
if err := e.client.NetworkRemove(noContext, n.Name); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("could not remove network '%s'", n.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,7 +233,7 @@ func (m *Metadata) EnvironDrone() map[string]string {
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
var pullRegexp = regexp.MustCompile("\\d+")
|
var pullRegexp = regexp.MustCompile(`\d+`)
|
||||||
|
|
||||||
func (m *Metadata) SetPlatform(platform string) {
|
func (m *Metadata) SetPlatform(platform string) {
|
||||||
if platform == "" {
|
if platform == "" {
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/pipeline/backend"
|
"github.com/woodpecker-ci/woodpecker/pipeline/backend"
|
||||||
"github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml"
|
"github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml"
|
||||||
)
|
)
|
||||||
|
@ -67,12 +69,14 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section
|
||||||
detached = true
|
detached = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if detached == false || len(container.Commands) != 0 {
|
if !detached || len(container.Commands) != 0 {
|
||||||
workingdir = path.Join(c.base, c.path)
|
workingdir = path.Join(c.base, c.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if detached == false {
|
if !detached {
|
||||||
paramsToEnv(container.Vargs, environment)
|
if err := paramsToEnv(container.Vargs, environment); err != nil {
|
||||||
|
log.Error().Err(err).Msg("paramsToEnv")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(container.Commands) != 0 {
|
if len(container.Commands) != 0 {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kr/pretty"
|
"github.com/kr/pretty"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParamsToEnv(t *testing.T) {
|
func TestParamsToEnv(t *testing.T) {
|
||||||
|
@ -28,7 +29,7 @@ func TestParamsToEnv(t *testing.T) {
|
||||||
"PLUGIN_COMPLEX": `[{"name":"Jack"},{"name":"Jill"}]`,
|
"PLUGIN_COMPLEX": `[{"name":"Jack"},{"name":"Jill"}]`,
|
||||||
}
|
}
|
||||||
got := map[string]string{}
|
got := map[string]string{}
|
||||||
paramsToEnv(from, got)
|
assert.NoError(t, paramsToEnv(from, got))
|
||||||
|
|
||||||
if !reflect.DeepEqual(want, got) {
|
if !reflect.DeepEqual(want, got) {
|
||||||
t.Errorf("Problem converting plugin parameters to environment variables")
|
t.Errorf("Problem converting plugin parameters to environment variables")
|
||||||
|
|
|
@ -164,8 +164,8 @@ func (c *ConstraintMap) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
|
||||||
out2 := map[string]string{}
|
out2 := map[string]string{}
|
||||||
|
|
||||||
unmarshal(&out1)
|
_ = unmarshal(&out1) // it contains include and exclude statement
|
||||||
unmarshal(&out2)
|
_ = unmarshal(&out2) // it contains no include/exclude statement, assume include as default
|
||||||
|
|
||||||
c.Include = out1.Include
|
c.Include = out1.Include
|
||||||
c.Exclude = out1.Exclude
|
c.Exclude = out1.Exclude
|
||||||
|
|
|
@ -3,6 +3,7 @@ package yaml
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/pipeline/frontend"
|
"github.com/woodpecker-ci/woodpecker/pipeline/frontend"
|
||||||
|
@ -142,7 +143,7 @@ func TestConstraint(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range testdata {
|
for _, test := range testdata {
|
||||||
c := parseConstraint(test.conf)
|
c := parseConstraint(t, test.conf)
|
||||||
got, want := c.Match(test.with), test.want
|
got, want := c.Match(test.with), test.want
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("Expect %q matches %q is %v", test.with, test.conf, want)
|
t.Errorf("Expect %q matches %q is %v", test.with, test.conf, want)
|
||||||
|
@ -250,7 +251,7 @@ func TestConstraintList(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range testdata {
|
for _, test := range testdata {
|
||||||
c := parseConstraintPath(test.conf)
|
c := parseConstraintPath(t, test.conf)
|
||||||
got, want := c.Match(test.with, test.message), test.want
|
got, want := c.Match(test.with, test.message), test.want
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("Expect %q matches %q should be %v got %v", test.with, test.conf, want, got)
|
t.Errorf("Expect %q matches %q should be %v got %v", test.with, test.conf, want, got)
|
||||||
|
@ -366,7 +367,7 @@ func TestConstraintMap(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range testdata {
|
for _, test := range testdata {
|
||||||
c := parseConstraintMap(test.conf)
|
c := parseConstraintMap(t, test.conf)
|
||||||
got, want := c.Match(test.with), test.want
|
got, want := c.Match(test.with), test.want
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("Expect %q matches %q is %v", test.with, test.conf, want)
|
t.Errorf("Expect %q matches %q is %v", test.with, test.conf, want)
|
||||||
|
@ -454,7 +455,7 @@ func TestConstraints(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range testdata {
|
for _, test := range testdata {
|
||||||
c := parseConstraints(test.conf)
|
c := parseConstraints(t, test.conf)
|
||||||
got, want := c.Match(test.with), test.want
|
got, want := c.Match(test.with), test.want
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("Expect %+v matches %q is %v", test.with, test.conf, want)
|
t.Errorf("Expect %+v matches %q is %v", test.with, test.conf, want)
|
||||||
|
@ -462,26 +463,26 @@ func TestConstraints(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseConstraints(s string) *Constraints {
|
func parseConstraints(t *testing.T, s string) *Constraints {
|
||||||
c := &Constraints{}
|
c := &Constraints{}
|
||||||
yaml.Unmarshal([]byte(s), c)
|
assert.NoError(t, yaml.Unmarshal([]byte(s), c))
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseConstraint(s string) *Constraint {
|
func parseConstraint(t *testing.T, s string) *Constraint {
|
||||||
c := &Constraint{}
|
c := &Constraint{}
|
||||||
yaml.Unmarshal([]byte(s), c)
|
assert.NoError(t, yaml.Unmarshal([]byte(s), c))
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseConstraintMap(s string) *ConstraintMap {
|
func parseConstraintMap(t *testing.T, s string) *ConstraintMap {
|
||||||
c := &ConstraintMap{}
|
c := &ConstraintMap{}
|
||||||
yaml.Unmarshal([]byte(s), c)
|
assert.NoError(t, yaml.Unmarshal([]byte(s), c))
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseConstraintPath(s string) *ConstraintPath {
|
func parseConstraintPath(t *testing.T, s string) *ConstraintPath {
|
||||||
c := &ConstraintPath{}
|
c := &ConstraintPath{}
|
||||||
yaml.Unmarshal([]byte(s), c)
|
assert.NoError(t, yaml.Unmarshal([]byte(s), c))
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ func (l *Linter) lint(containers []*yaml.Container, block uint8) error {
|
||||||
if err := l.lintImage(container); err != nil {
|
if err := l.lintImage(container); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if l.trusted == false {
|
if !l.trusted {
|
||||||
if err := l.lintTrusted(container); err != nil {
|
if err := l.lintTrusted(container); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@ type BoolTrue struct {
|
||||||
// UnmarshalYAML implements custom Yaml unmarshaling.
|
// UnmarshalYAML implements custom Yaml unmarshaling.
|
||||||
func (b *BoolTrue) UnmarshalYAML(value *yaml.Node) error {
|
func (b *BoolTrue) UnmarshalYAML(value *yaml.Node) error {
|
||||||
var s string
|
var s string
|
||||||
value.Decode(&s)
|
if err := value.Decode(&s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
v, err := strconv.ParseBool(s)
|
v, err := strconv.ParseBool(s)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -16,7 +16,7 @@ type StructStringorInt struct {
|
||||||
func TestStringorIntYaml(t *testing.T) {
|
func TestStringorIntYaml(t *testing.T) {
|
||||||
for _, str := range []string{`{foo: 10}`, `{foo: "10"}`} {
|
for _, str := range []string{`{foo: 10}`, `{foo: "10"}`} {
|
||||||
s := StructStringorInt{}
|
s := StructStringorInt{}
|
||||||
yaml.Unmarshal([]byte(str), &s)
|
assert.NoError(t, yaml.Unmarshal([]byte(str), &s))
|
||||||
|
|
||||||
assert.Equal(t, StringorInt(10), s.Foo)
|
assert.Equal(t, StringorInt(10), s.Foo)
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ func TestStringorIntYaml(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
s2 := StructStringorInt{}
|
s2 := StructStringorInt{}
|
||||||
yaml.Unmarshal(d, &s2)
|
assert.NoError(t, yaml.Unmarshal(d, &s2))
|
||||||
|
|
||||||
assert.Equal(t, StringorInt(10), s2.Foo)
|
assert.Equal(t, StringorInt(10), s2.Foo)
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ func TestStringorsliceYaml(t *testing.T) {
|
||||||
str := `{foo: [bar, baz]}`
|
str := `{foo: [bar, baz]}`
|
||||||
|
|
||||||
s := StructStringorslice{}
|
s := StructStringorslice{}
|
||||||
yaml.Unmarshal([]byte(str), &s)
|
assert.NoError(t, yaml.Unmarshal([]byte(str), &s))
|
||||||
|
|
||||||
assert.Equal(t, Stringorslice{"bar", "baz"}, s.Foo)
|
assert.Equal(t, Stringorslice{"bar", "baz"}, s.Foo)
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ func TestStringorsliceYaml(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
s2 := StructStringorslice{}
|
s2 := StructStringorslice{}
|
||||||
yaml.Unmarshal(d, &s2)
|
assert.NoError(t, yaml.Unmarshal(d, &s2))
|
||||||
|
|
||||||
assert.Equal(t, Stringorslice{"bar", "baz"}, s2.Foo)
|
assert.Equal(t, Stringorslice{"bar", "baz"}, s2.Foo)
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ func TestSliceOrMapYaml(t *testing.T) {
|
||||||
str := `{foos: [bar=baz, far=faz]}`
|
str := `{foos: [bar=baz, far=faz]}`
|
||||||
|
|
||||||
s := StructSliceorMap{}
|
s := StructSliceorMap{}
|
||||||
yaml.Unmarshal([]byte(str), &s)
|
assert.NoError(t, yaml.Unmarshal([]byte(str), &s))
|
||||||
|
|
||||||
assert.Equal(t, SliceorMap{"bar": "baz", "far": "faz"}, s.Foos)
|
assert.Equal(t, SliceorMap{"bar": "baz", "far": "faz"}, s.Foos)
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ func TestSliceOrMapYaml(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
s2 := StructSliceorMap{}
|
s2 := StructSliceorMap{}
|
||||||
yaml.Unmarshal(d, &s2)
|
assert.NoError(t, yaml.Unmarshal(d, &s2))
|
||||||
|
|
||||||
assert.Equal(t, SliceorMap{"bar": "baz", "far": "faz"}, s2.Foos)
|
assert.Equal(t, SliceorMap{"bar": "baz", "far": "faz"}, s2.Foos)
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ func TestStr2SliceOrMapPtrMap(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
s2 := map[string]*StructSliceorMap{}
|
s2 := map[string]*StructSliceorMap{}
|
||||||
yaml.Unmarshal(d, &s2)
|
assert.NoError(t, yaml.Unmarshal(d, &s2))
|
||||||
|
|
||||||
assert.Equal(t, s, s2)
|
assert.Equal(t, s, s2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/pipeline/backend"
|
"github.com/woodpecker-ci/woodpecker/pipeline/backend"
|
||||||
|
@ -55,7 +56,9 @@ func New(spec *backend.Config, opts ...Option) *Runtime {
|
||||||
// Run starts the runtime and waits for it to complete.
|
// Run starts the runtime and waits for it to complete.
|
||||||
func (r *Runtime) Run() error {
|
func (r *Runtime) Run() error {
|
||||||
defer func() {
|
defer func() {
|
||||||
r.engine.Destroy(r.ctx, r.spec)
|
if err := r.engine.Destroy(r.ctx, r.spec); err != nil {
|
||||||
|
log.Error().Err(err).Msg("could not destroy engine")
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.started = time.Now().Unix()
|
r.started = time.Now().Unix()
|
||||||
|
@ -105,9 +108,9 @@ func (r *Runtime) execAll(procs []*backend.Step) <-chan error {
|
||||||
|
|
||||||
func (r *Runtime) exec(proc *backend.Step) error {
|
func (r *Runtime) exec(proc *backend.Step) error {
|
||||||
switch {
|
switch {
|
||||||
case r.err != nil && proc.OnFailure == false:
|
case r.err != nil && !proc.OnFailure:
|
||||||
return nil
|
return nil
|
||||||
case r.err == nil && proc.OnSuccess == false:
|
case r.err == nil && !proc.OnSuccess:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,8 +138,10 @@ func (r *Runtime) exec(proc *backend.Step) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
r.logger.Log(proc, multipart.New(rc))
|
if err := r.logger.Log(proc, multipart.New(rc)); err != nil {
|
||||||
rc.Close()
|
log.Error().Err(err).Msg("process logging failed")
|
||||||
|
}
|
||||||
|
_ = rc.Close()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,9 @@ func (c *client) Next(ctx context.Context, f Filter) (*Pipeline, error) {
|
||||||
p.ID = res.GetPipeline().GetId()
|
p.ID = res.GetPipeline().GetId()
|
||||||
p.Timeout = res.GetPipeline().GetTimeout()
|
p.Timeout = res.GetPipeline().GetTimeout()
|
||||||
p.Config = new(backend.Config)
|
p.Config = new(backend.Config)
|
||||||
json.Unmarshal(res.GetPipeline().GetPayload(), p.Config)
|
if err := json.Unmarshal(res.GetPipeline().GetPayload(), p.Config); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("could not unmarshal pipeline config of '%s'", p.ID)
|
||||||
|
}
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Identifies the type of line in the logs.
|
// Identifies the type of line in the logs.
|
||||||
|
@ -78,7 +80,9 @@ func (w *LineWriter) Write(p []byte) (n int, err error) {
|
||||||
Time: int64(time.Since(w.now).Seconds()),
|
Time: int64(time.Since(w.now).Seconds()),
|
||||||
Type: LineStdout,
|
Type: LineStdout,
|
||||||
}
|
}
|
||||||
w.peer.Log(context.Background(), w.id, line)
|
if err := w.peer.Log(context.Background(), w.id, line); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("fail to write pipeline log to peer '%s'", w.id)
|
||||||
|
}
|
||||||
w.num++
|
w.num++
|
||||||
|
|
||||||
// for _, part := range bytes.Split(p, []byte{'\n'}) {
|
// for _, part := range bytes.Split(p, []byte{'\n'}) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -42,7 +41,7 @@ func GetBuilds(c *gin.Context) {
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
|
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,13 +63,13 @@ func GetBuild(c *gin.Context) {
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := store_.GetBuildNumber(repo, num)
|
build, err := store_.GetBuildNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
files, _ := store_.FileList(build)
|
files, _ := store_.FileList(build)
|
||||||
|
@ -109,26 +108,28 @@ func GetBuildLogs(c *gin.Context) {
|
||||||
|
|
||||||
build, err := store_.GetBuildNumber(repo, num)
|
build, err := store_.GetBuildNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := store_.ProcChild(build, ppid, name)
|
proc, err := store_.ProcChild(build, ppid, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rc, err := store_.LogFind(proc)
|
rc, err := store_.LogFind(proc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rc.Close()
|
defer rc.Close()
|
||||||
|
|
||||||
c.Header("Content-Type", "application/json")
|
c.Header("Content-Type", "application/json")
|
||||||
io.Copy(c.Writer, rc)
|
if _, err := io.Copy(c.Writer, rc); err != nil {
|
||||||
|
log.Error().Err(err).Msg("could not copy log to http response")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetProcLogs(c *gin.Context) {
|
func GetProcLogs(c *gin.Context) {
|
||||||
|
@ -142,26 +143,28 @@ func GetProcLogs(c *gin.Context) {
|
||||||
|
|
||||||
build, err := store_.GetBuildNumber(repo, num)
|
build, err := store_.GetBuildNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := store_.ProcFind(build, pid)
|
proc, err := store_.ProcFind(build, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rc, err := store_.LogFind(proc)
|
rc, err := store_.LogFind(proc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rc.Close()
|
defer rc.Close()
|
||||||
|
|
||||||
c.Header("Content-Type", "application/json")
|
c.Header("Content-Type", "application/json")
|
||||||
io.Copy(c.Writer, rc)
|
if _, err := io.Copy(c.Writer, rc); err != nil {
|
||||||
|
log.Error().Err(err).Msg("could not copy log to http response")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBuild cancels a build
|
// DeleteBuild cancels a build
|
||||||
|
@ -203,9 +206,19 @@ func DeleteBuild(c *gin.Context) {
|
||||||
procToEvict = append(procToEvict, fmt.Sprint(proc.ID))
|
procToEvict = append(procToEvict, fmt.Sprint(proc.ID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
server.Config.Services.Queue.EvictAtOnce(context.Background(), procToEvict)
|
|
||||||
server.Config.Services.Queue.ErrorAtOnce(context.Background(), procToEvict, queue.ErrCancel)
|
if err := server.Config.Services.Queue.EvictAtOnce(c, procToEvict); err != nil {
|
||||||
server.Config.Services.Queue.ErrorAtOnce(context.Background(), procToCancel, queue.ErrCancel)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := server.Config.Services.Queue.ErrorAtOnce(c, procToEvict, queue.ErrCancel); err != nil {
|
||||||
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := server.Config.Services.Queue.ErrorAtOnce(c, procToCancel, queue.ErrCancel); err != nil {
|
||||||
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Then update the DB status for pending builds
|
// Then update the DB status for pending builds
|
||||||
// Running ones will be set when the agents stop on the cancel signal
|
// Running ones will be set when the agents stop on the cancel signal
|
||||||
|
@ -225,7 +238,7 @@ func DeleteBuild(c *gin.Context) {
|
||||||
|
|
||||||
killedBuild, err := shared.UpdateToStatusKilled(store_, *build)
|
killedBuild, err := shared.UpdateToStatusKilled(store_, *build)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(500, err)
|
_ = c.AbortWithError(500, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,11 +247,13 @@ func DeleteBuild(c *gin.Context) {
|
||||||
if build.Status == model.StatusPending {
|
if build.Status == model.StatusPending {
|
||||||
procs, err = store_.ProcList(killedBuild)
|
procs, err = store_.ProcList(killedBuild)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
killedBuild.Procs = model.Tree(procs)
|
killedBuild.Procs = model.Tree(procs)
|
||||||
publishToTopic(c, killedBuild, repo, model.Cancelled)
|
if err := publishToTopic(c, killedBuild, repo, model.Cancelled); err != nil {
|
||||||
|
log.Error().Err(err).Msg("publishToTopic")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.String(204, "")
|
c.String(204, "")
|
||||||
|
@ -255,7 +270,7 @@ func PostApproval(c *gin.Context) {
|
||||||
|
|
||||||
build, err := store_.GetBuildNumber(repo, num)
|
build, err := store_.GetBuildNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if build.Status != model.StatusBlocked {
|
if build.Status != model.StatusBlocked {
|
||||||
|
@ -267,7 +282,7 @@ func PostApproval(c *gin.Context) {
|
||||||
configs, err := server.Config.Storage.Config.ConfigsForBuild(build.ID)
|
configs, err := server.Config.Storage.Config.ConfigsForBuild(build.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to get build config for %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to get build config for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,8 +362,12 @@ func PostApproval(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
publishToTopic(c, build, repo, model.Enqueued)
|
if err := publishToTopic(c, build, repo, model.Enqueued); err != nil {
|
||||||
queueBuild(build, repo, buildItems)
|
log.Error().Err(err).Msg("publishToTopic")
|
||||||
|
}
|
||||||
|
if err := queueBuild(build, repo, buildItems); err != nil {
|
||||||
|
log.Error().Err(err).Msg("queueBuild")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostDecline(c *gin.Context) {
|
func PostDecline(c *gin.Context) {
|
||||||
|
@ -363,7 +382,7 @@ func PostDecline(c *gin.Context) {
|
||||||
|
|
||||||
build, err := store_.GetBuildNumber(repo, num)
|
build, err := store_.GetBuildNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if build.Status != model.StatusBlocked {
|
if build.Status != model.StatusBlocked {
|
||||||
|
@ -402,21 +421,21 @@ func PostBuild(c *gin.Context) {
|
||||||
|
|
||||||
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := store_.GetUser(repo.UserID)
|
user, err := store_.GetUser(repo.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to find repo owner %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to find repo owner %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(500, err)
|
_ = c.AbortWithError(500, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := store_.GetBuildNumber(repo, num)
|
build, err := store_.GetBuildNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to get build %d. %s", num, err)
|
log.Error().Msgf("failure to get build %d. %s", num, err)
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,9 +450,13 @@ func PostBuild(c *gin.Context) {
|
||||||
// may be stale. Therefore, we should refresh prior to dispatching
|
// may be stale. Therefore, we should refresh prior to dispatching
|
||||||
// the job.
|
// the job.
|
||||||
if refresher, ok := remote_.(remote.Refresher); ok {
|
if refresher, ok := remote_.(remote.Refresher); ok {
|
||||||
ok, _ := refresher.Refresh(c, user)
|
ok, err := refresher.Refresh(c, user)
|
||||||
if ok {
|
if err != nil {
|
||||||
store_.UpdateUser(user)
|
log.Error().Err(err).Msgf("refresh oauth token of user '%s' failed", user.Login)
|
||||||
|
} else if ok {
|
||||||
|
if err := store_.UpdateUser(user); err != nil {
|
||||||
|
log.Error().Err(err).Msg("fail to save user to store after refresh oauth token")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,14 +464,14 @@ func PostBuild(c *gin.Context) {
|
||||||
configs, err := server.Config.Storage.Config.ConfigsForBuild(build.ID)
|
configs, err := server.Config.Storage.Config.ConfigsForBuild(build.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to get build config for %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to get build config for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
netrc, err := remote_.Netrc(user, repo)
|
netrc, err := remote_.Netrc(user, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to generate netrc for %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to generate netrc for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(500, err)
|
_ = c.AbortWithError(500, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,7 +502,7 @@ func PostBuild(c *gin.Context) {
|
||||||
err = persistBuildConfigs(configs, build.ID)
|
err = persistBuildConfigs(configs, build.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to persist build config for %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to persist build config for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(500, err)
|
_ = c.AbortWithError(500, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,8 +575,12 @@ func PostBuild(c *gin.Context) {
|
||||||
}
|
}
|
||||||
c.JSON(202, build)
|
c.JSON(202, build)
|
||||||
|
|
||||||
publishToTopic(c, build, repo, model.Enqueued)
|
if err := publishToTopic(c, build, repo, model.Enqueued); err != nil {
|
||||||
queueBuild(build, repo, buildItems)
|
log.Error().Err(err).Msg("publishToTopic")
|
||||||
|
}
|
||||||
|
if err := queueBuild(build, repo, buildItems); err != nil {
|
||||||
|
log.Error().Err(err).Msg("queueBuild")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteBuildLogs(c *gin.Context) {
|
func DeleteBuildLogs(c *gin.Context) {
|
||||||
|
@ -565,13 +592,13 @@ func DeleteBuildLogs(c *gin.Context) {
|
||||||
|
|
||||||
build, err := store_.GetBuildNumber(repo, num)
|
build, err := store_.GetBuildNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
procs, err := store_.ProcList(build)
|
procs, err := store_.ProcList(build)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
|
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
|
@ -31,20 +32,20 @@ func FileList(c *gin.Context) {
|
||||||
store_ := store.FromContext(c)
|
store_ := store.FromContext(c)
|
||||||
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
build, err := store_.GetBuildNumber(repo, num)
|
build, err := store_.GetBuildNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
files, err := store_.FileList(build)
|
files, err := store_.FileList(build)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,25 +66,25 @@ func FileGet(c *gin.Context) {
|
||||||
|
|
||||||
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pid, err := strconv.Atoi(c.Param("proc"))
|
pid, err := strconv.Atoi(c.Param("proc"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := store_.GetBuildNumber(repo, num)
|
build, err := store_.GetBuildNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := store_.ProcFind(build, pid)
|
proc, err := store_.ProcFind(build, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,5 +111,7 @@ func FileGet(c *gin.Context) {
|
||||||
c.Header("Content-Type", "application/json")
|
c.Header("Content-Type", "application/json")
|
||||||
}
|
}
|
||||||
|
|
||||||
io.Copy(c.Writer, rc)
|
if _, err := io.Copy(c.Writer, rc); err != nil {
|
||||||
|
log.Error().Err(err).Msg("could not copy file to http response")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ func PostHook(c *gin.Context) {
|
||||||
tmpRepo, build, err := remote_.Hook(c.Request)
|
tmpRepo, build, err := remote_.Hook(c.Request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to parse hook. %s", err)
|
log.Error().Msgf("failure to parse hook. %s", err)
|
||||||
c.AbortWithError(400, err)
|
_ = c.AbortWithError(400, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if build == nil {
|
if build == nil {
|
||||||
|
@ -107,12 +107,12 @@ func PostHook(c *gin.Context) {
|
||||||
repo, err := store_.GetRepoName(tmpRepo.Owner + "/" + tmpRepo.Name)
|
repo, err := store_.GetRepoName(tmpRepo.Owner + "/" + tmpRepo.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to find repo %s/%s from hook. %s", tmpRepo.Owner, tmpRepo.Name, err)
|
log.Error().Msgf("failure to find repo %s/%s from hook. %s", tmpRepo.Owner, tmpRepo.Name, err)
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !repo.IsActive {
|
if !repo.IsActive {
|
||||||
log.Error().Msgf("ignoring hook. %s/%s is inactive.", tmpRepo.Owner, tmpRepo.Name)
|
log.Error().Msgf("ignoring hook. %s/%s is inactive.", tmpRepo.Owner, tmpRepo.Name)
|
||||||
c.AbortWithError(204, err)
|
_ = c.AbortWithError(204, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ func PostHook(c *gin.Context) {
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to parse token from hook for %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to parse token from hook for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(400, err)
|
_ = c.AbortWithError(400, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if parsed.Text != repo.FullName {
|
if parsed.Text != repo.FullName {
|
||||||
|
@ -139,7 +139,7 @@ func PostHook(c *gin.Context) {
|
||||||
|
|
||||||
if build.Event == model.EventPull && !repo.AllowPull {
|
if build.Event == model.EventPull && !repo.AllowPull {
|
||||||
log.Info().Msgf("ignoring hook. repo %s is disabled for pull requests.", repo.FullName)
|
log.Info().Msgf("ignoring hook. repo %s is disabled for pull requests.", repo.FullName)
|
||||||
c.Writer.Write([]byte("pulls are disabled on woodpecker for this repo"))
|
_, _ = c.Writer.Write([]byte("pulls are disabled on woodpecker for this repo"))
|
||||||
c.Writer.WriteHeader(204)
|
c.Writer.WriteHeader(204)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ func PostHook(c *gin.Context) {
|
||||||
user, err := store_.GetUser(repo.UserID)
|
user, err := store_.GetUser(repo.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to find repo owner %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to find repo owner %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(500, err)
|
_ = c.AbortWithError(500, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,14 +171,14 @@ func PostHook(c *gin.Context) {
|
||||||
remoteYamlConfigs, err := configFetcher.Fetch(c)
|
remoteYamlConfigs, err := configFetcher.Fetch(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: %s: cannot find %s in %s: %s", repo.FullName, repo.Config, build.Ref, err)
|
log.Error().Msgf("error: %s: cannot find %s in %s: %s", repo.FullName, repo.Config, build.Ref, err)
|
||||||
c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
filtered, err := branchFiltered(build, remoteYamlConfigs)
|
filtered, err := branchFiltered(build, remoteYamlConfigs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to parse yaml from hook for %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to parse yaml from hook for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(400, err)
|
_ = c.AbortWithError(400, err)
|
||||||
}
|
}
|
||||||
if filtered {
|
if filtered {
|
||||||
c.String(200, "Branch does not match restrictions defined in yaml")
|
c.String(200, "Branch does not match restrictions defined in yaml")
|
||||||
|
@ -202,7 +202,7 @@ func PostHook(c *gin.Context) {
|
||||||
err = store_.CreateBuild(build, build.Procs...)
|
err = store_.CreateBuild(build, build.Procs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to save commit for %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to save commit for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(500, err)
|
_ = c.AbortWithError(500, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ func PostHook(c *gin.Context) {
|
||||||
_, err := findOrPersistPipelineConfig(repo, build, remoteYamlConfig)
|
_, err := findOrPersistPipelineConfig(repo, build, remoteYamlConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to find or persist build config for %s. %s", repo.FullName, err)
|
log.Error().Msgf("failure to find or persist build config for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(500, err)
|
_ = c.AbortWithError(500, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,8 +288,12 @@ func PostHook(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
publishToTopic(c, build, repo, model.Enqueued)
|
if err := publishToTopic(c, build, repo, model.Enqueued); err != nil {
|
||||||
queueBuild(build, repo, buildItems)
|
log.Error().Err(err).Msg("publishToTopic")
|
||||||
|
}
|
||||||
|
if err := queueBuild(build, repo, buildItems); err != nil {
|
||||||
|
log.Error().Err(err).Msg("queueBuild")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: parse yaml once and not for each filter function
|
// TODO: parse yaml once and not for each filter function
|
||||||
|
@ -367,7 +371,7 @@ func findOrPersistPipelineConfig(repo *model.Repo, build *model.Build, remoteYam
|
||||||
}
|
}
|
||||||
|
|
||||||
// publishes message to UI clients
|
// publishes message to UI clients
|
||||||
func publishToTopic(c *gin.Context, build *model.Build, repo *model.Repo, event model.EventType) {
|
func publishToTopic(c *gin.Context, build *model.Build, repo *model.Repo, event model.EventType) error {
|
||||||
message := pubsub.Message{
|
message := pubsub.Message{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"repo": repo.FullName,
|
"repo": repo.FullName,
|
||||||
|
@ -381,10 +385,10 @@ func publishToTopic(c *gin.Context, build *model.Build, repo *model.Repo, event
|
||||||
Repo: *repo,
|
Repo: *repo,
|
||||||
Build: buildCopy,
|
Build: buildCopy,
|
||||||
})
|
})
|
||||||
server.Config.Services.Pubsub.Publish(c, "topic/events", message)
|
return server.Config.Services.Pubsub.Publish(c, "topic/events", message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.BuildItem) {
|
func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.BuildItem) error {
|
||||||
var tasks []*queue.Task
|
var tasks []*queue.Task
|
||||||
for _, item := range buildItems {
|
for _, item := range buildItems {
|
||||||
if item.Proc.State == model.StatusSkipped {
|
if item.Proc.State == model.StatusSkipped {
|
||||||
|
@ -408,10 +412,12 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build
|
||||||
Timeout: repo.Timeout,
|
Timeout: repo.Timeout,
|
||||||
})
|
})
|
||||||
|
|
||||||
server.Config.Services.Logs.Open(context.Background(), task.ID)
|
if err := server.Config.Services.Logs.Open(context.Background(), task.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
tasks = append(tasks, task)
|
tasks = append(tasks, task)
|
||||||
}
|
}
|
||||||
server.Config.Services.Queue.PushAtOnce(context.Background(), tasks)
|
return server.Config.Services.Queue.PushAtOnce(context.Background(), tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func taskIds(dependsOn []string, buildItems []*shared.BuildItem) (taskIds []string) {
|
func taskIds(dependsOn []string, buildItems []*shared.BuildItem) (taskIds []string) {
|
||||||
|
|
|
@ -83,7 +83,7 @@ func HandleAuth(c *gin.Context) {
|
||||||
// check the user's organization membership.
|
// check the user's organization membership.
|
||||||
if len(config.Orgs) != 0 {
|
if len(config.Orgs) != 0 {
|
||||||
teams, terr := remote.Teams(c, tmpuser)
|
teams, terr := remote.Teams(c, tmpuser)
|
||||||
if terr != nil || config.IsMember(teams) == false {
|
if terr != nil || !config.IsMember(teams) {
|
||||||
log.Error().Msgf("cannot verify team membership for %s.", u.Login)
|
log.Error().Msgf("cannot verify team membership for %s.", u.Login)
|
||||||
c.Redirect(303, "/login?error=access_denied")
|
c.Redirect(303, "/login?error=access_denied")
|
||||||
return
|
return
|
||||||
|
@ -120,7 +120,7 @@ func HandleAuth(c *gin.Context) {
|
||||||
// check the user's organization membership.
|
// check the user's organization membership.
|
||||||
if len(config.Orgs) != 0 {
|
if len(config.Orgs) != 0 {
|
||||||
teams, terr := remote.Teams(c, u)
|
teams, terr := remote.Teams(c, u)
|
||||||
if terr != nil || config.IsMember(teams) == false {
|
if terr != nil || !config.IsMember(teams) {
|
||||||
log.Error().Msgf("cannot verify team membership for %s.", u.Login)
|
log.Error().Msgf("cannot verify team membership for %s.", u.Login)
|
||||||
c.Redirect(303, "/login?error=access_denied")
|
c.Redirect(303, "/login?error=access_denied")
|
||||||
return
|
return
|
||||||
|
@ -163,32 +163,32 @@ func GetLoginToken(c *gin.Context) {
|
||||||
in := &tokenPayload{}
|
in := &tokenPayload{}
|
||||||
err := c.Bind(in)
|
err := c.Bind(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
login, err := remote.Auth(c, in.Access, in.Refresh)
|
login, err := remote.Auth(c, in.Access, in.Refresh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusUnauthorized, err)
|
_ = c.AbortWithError(http.StatusUnauthorized, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := store_.GetUserLogin(login)
|
user, err := store_.GetUserLogin(login)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusNotFound, err)
|
_ = c.AbortWithError(http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
exp := time.Now().Add(server.Config.Server.SessionExpires).Unix()
|
exp := time.Now().Add(server.Config.Server.SessionExpires).Unix()
|
||||||
token := token.New(token.SessToken, user.Login)
|
newToken := token.New(token.SessToken, user.Login)
|
||||||
tokenstr, err := token.SignExpires(user.Hash, exp)
|
tokenStr, err := newToken.SignExpires(user.Hash, exp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, &tokenPayload{
|
c.JSON(http.StatusOK, &tokenPayload{
|
||||||
Access: tokenstr,
|
Access: tokenStr,
|
||||||
Expires: exp - time.Now().Unix(),
|
Expires: exp - time.Now().Unix(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/securecookie"
|
"github.com/gorilla/securecookie"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server"
|
"github.com/woodpecker-ci/woodpecker/server"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/model"
|
"github.com/woodpecker-ci/woodpecker/server/model"
|
||||||
|
@ -104,7 +105,7 @@ func PatchRepo(c *gin.Context) {
|
||||||
|
|
||||||
in := new(model.RepoPatch)
|
in := new(model.RepoPatch)
|
||||||
if err := c.Bind(in); err != nil {
|
if err := c.Bind(in); err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +144,7 @@ func PatchRepo(c *gin.Context) {
|
||||||
|
|
||||||
err := store_.UpdateRepo(repo)
|
err := store_.UpdateRepo(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ func ChownRepo(c *gin.Context) {
|
||||||
|
|
||||||
err := store_.UpdateRepo(repo)
|
err := store_.UpdateRepo(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, repo)
|
c.JSON(http.StatusOK, repo)
|
||||||
|
@ -180,7 +181,7 @@ func GetRepoBranches(c *gin.Context) {
|
||||||
|
|
||||||
branches, err := r.Branches(c, user, repo)
|
branches, err := r.Branches(c, user, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,20 +201,20 @@ func DeleteRepo(c *gin.Context) {
|
||||||
|
|
||||||
err := store_.UpdateRepo(repo)
|
err := store_.UpdateRepo(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if remove {
|
if remove {
|
||||||
err := store_.DeleteRepo(repo)
|
err := store_.DeleteRepo(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := remote_.Deactivate(c, user, repo, server.Config.Server.Host); err != nil {
|
if err := remote_.Deactivate(c, user, repo, server.Config.Server.Host); err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(200, repo)
|
c.JSON(200, repo)
|
||||||
|
@ -241,15 +242,20 @@ func RepairRepo(c *gin.Context) {
|
||||||
sig,
|
sig,
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = remote_.Deactivate(c, user, repo, host)
|
if err := remote_.Deactivate(c, user, repo, host); err != nil {
|
||||||
err = remote_.Activate(c, user, repo, link)
|
log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName)
|
||||||
if err != nil {
|
}
|
||||||
|
if err := remote_.Activate(c, user, repo, link); err != nil {
|
||||||
c.String(500, err.Error())
|
c.String(500, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
from, err := remote_.Repo(c, user, repo.Owner, repo.Name)
|
from, err := remote_.Repo(c, user, repo.Owner, repo.Name)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("get repo '%s/%s' from remote", repo.Owner, repo.Name)
|
||||||
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
repo.Name = from.Name
|
repo.Name = from.Name
|
||||||
repo.Owner = from.Owner
|
repo.Owner = from.Owner
|
||||||
repo.FullName = from.FullName
|
repo.FullName = from.FullName
|
||||||
|
@ -260,7 +266,9 @@ func RepairRepo(c *gin.Context) {
|
||||||
if repo.IsSCMPrivate != from.IsSCMPrivate {
|
if repo.IsSCMPrivate != from.IsSCMPrivate {
|
||||||
repo.ResetVisibility()
|
repo.ResetVisibility()
|
||||||
}
|
}
|
||||||
store_.UpdateRepo(repo)
|
if err := store_.UpdateRepo(repo); err != nil {
|
||||||
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Writer.WriteHeader(http.StatusOK)
|
c.Writer.WriteHeader(http.StatusOK)
|
||||||
|
@ -275,19 +283,19 @@ func MoveRepo(c *gin.Context) {
|
||||||
to, exists := c.GetQuery("to")
|
to, exists := c.GetQuery("to")
|
||||||
if !exists {
|
if !exists {
|
||||||
err := fmt.Errorf("Missing required to query value")
|
err := fmt.Errorf("Missing required to query value")
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
owner, name, errParse := model.ParseRepo(to)
|
owner, name, errParse := model.ParseRepo(to)
|
||||||
if errParse != nil {
|
if errParse != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, errParse)
|
_ = c.AbortWithError(http.StatusInternalServerError, errParse)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
from, err := remote_.Repo(c, user, owner, name)
|
from, err := remote_.Repo(c, user, owner, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !from.Perm.Admin {
|
if !from.Perm.Admin {
|
||||||
|
@ -308,7 +316,7 @@ func MoveRepo(c *gin.Context) {
|
||||||
|
|
||||||
errStore := store_.UpdateRepo(repo)
|
errStore := store_.UpdateRepo(repo)
|
||||||
if errStore != nil {
|
if errStore != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, errStore)
|
_ = c.AbortWithError(http.StatusInternalServerError, errStore)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,10 +336,10 @@ func MoveRepo(c *gin.Context) {
|
||||||
sig,
|
sig,
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: check if we should handle that error
|
if err := remote_.Deactivate(c, user, repo, host); err != nil {
|
||||||
remote_.Deactivate(c, user, repo, host)
|
log.Trace().Err(err).Msgf("deactivate repo '%s' for move to activate later, got an error", repo.FullName)
|
||||||
err = remote_.Activate(c, user, repo, link)
|
}
|
||||||
if err != nil {
|
if err := remote_.Activate(c, user, repo, link); err != nil {
|
||||||
c.String(500, err.Error())
|
c.String(500, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func EventStreamSSE(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ping the client
|
// ping the client
|
||||||
io.WriteString(rw, ": ping\n\n")
|
logWriteStringErr(io.WriteString(rw, ": ping\n\n"))
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
|
|
||||||
log.Debug().Msg("user feed: connection opened")
|
log.Debug().Msg("user feed: connection opened")
|
||||||
|
@ -78,9 +78,10 @@ func EventStreamSSE(c *gin.Context) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
server.Config.Services.Pubsub.Subscribe(ctx, "topic/events", func(m pubsub.Message) {
|
err := server.Config.Services.Pubsub.Subscribe(ctx, "topic/events", func(m pubsub.Message) {
|
||||||
defer func() {
|
defer func() {
|
||||||
recover() // fix #2480
|
obj := recover() // fix #2480 // TODO: check if it's still needed
|
||||||
|
log.Trace().Msgf("pubsub subscribe recover return: %v", obj)
|
||||||
}()
|
}()
|
||||||
name := m.Labels["repo"]
|
name := m.Labels["repo"]
|
||||||
priv := m.Labels["private"]
|
priv := m.Labels["private"]
|
||||||
|
@ -93,6 +94,9 @@ func EventStreamSSE(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("Subscribe failed")
|
||||||
|
}
|
||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -103,13 +107,13 @@ func EventStreamSSE(c *gin.Context) {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
case <-time.After(time.Second * 30):
|
case <-time.After(time.Second * 30):
|
||||||
io.WriteString(rw, ": ping\n\n")
|
logWriteStringErr(io.WriteString(rw, ": ping\n\n"))
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
case buf, ok := <-eventc:
|
case buf, ok := <-eventc:
|
||||||
if ok {
|
if ok {
|
||||||
io.WriteString(rw, "data: ")
|
logWriteStringErr(io.WriteString(rw, "data: "))
|
||||||
rw.Write(buf)
|
logWriteStringErr(rw.Write(buf))
|
||||||
io.WriteString(rw, "\n\n")
|
logWriteStringErr(io.WriteString(rw, "\n\n"))
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +134,7 @@ func LogStreamSSE(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
io.WriteString(rw, ": ping\n\n")
|
logWriteStringErr(io.WriteString(rw, ": ping\n\n"))
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
|
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
|
@ -144,18 +148,18 @@ func LogStreamSSE(c *gin.Context) {
|
||||||
build, err := store_.GetBuildNumber(repo, buildn)
|
build, err := store_.GetBuildNumber(repo, buildn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug().Msgf("stream cannot get build number: %v", err)
|
log.Debug().Msgf("stream cannot get build number: %v", err)
|
||||||
io.WriteString(rw, "event: error\ndata: build not found\n\n")
|
logWriteStringErr(io.WriteString(rw, "event: error\ndata: build not found\n\n"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
proc, err := store_.ProcFind(build, jobn)
|
proc, err := store_.ProcFind(build, jobn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug().Msgf("stream cannot get proc number: %v", err)
|
log.Debug().Msgf("stream cannot get proc number: %v", err)
|
||||||
io.WriteString(rw, "event: error\ndata: process not found\n\n")
|
logWriteStringErr(io.WriteString(rw, "event: error\ndata: process not found\n\n"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if proc.State != model.StatusRunning {
|
if proc.State != model.StatusRunning {
|
||||||
log.Debug().Msg("stream not found.")
|
log.Debug().Msg("stream not found.")
|
||||||
io.WriteString(rw, "event: error\ndata: stream not found\n\n")
|
logWriteStringErr(io.WriteString(rw, "event: error\ndata: stream not found\n\n"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +178,10 @@ func LogStreamSSE(c *gin.Context) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// TODO remove global variable
|
// TODO remove global variable
|
||||||
server.Config.Services.Logs.Tail(ctx, fmt.Sprint(proc.ID), func(entries ...*logging.Entry) {
|
err := server.Config.Services.Logs.Tail(ctx, fmt.Sprint(proc.ID), func(entries ...*logging.Entry) {
|
||||||
defer func() {
|
defer func() {
|
||||||
recover() // fix #2480
|
obj := recover() // fix #2480 // TODO: check if it's still needed
|
||||||
|
log.Trace().Msgf("pubsub subscribe recover return: %v", obj)
|
||||||
}()
|
}()
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
select {
|
select {
|
||||||
|
@ -187,8 +192,11 @@ func LogStreamSSE(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("tail of logs failed")
|
||||||
|
}
|
||||||
|
|
||||||
io.WriteString(rw, "event: error\ndata: eof\n\n")
|
logWriteStringErr(io.WriteString(rw, "event: error\ndata: eof\n\n"))
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
|
@ -215,16 +223,16 @@ func LogStreamSSE(c *gin.Context) {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
case <-time.After(time.Second * 30):
|
case <-time.After(time.Second * 30):
|
||||||
io.WriteString(rw, ": ping\n\n")
|
logWriteStringErr(io.WriteString(rw, ": ping\n\n"))
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
case buf, ok := <-logc:
|
case buf, ok := <-logc:
|
||||||
if ok {
|
if ok {
|
||||||
if id > last {
|
if id > last {
|
||||||
io.WriteString(rw, "id: "+strconv.Itoa(id))
|
logWriteStringErr(io.WriteString(rw, "id: "+strconv.Itoa(id)))
|
||||||
io.WriteString(rw, "\n")
|
logWriteStringErr(io.WriteString(rw, "\n"))
|
||||||
io.WriteString(rw, "data: ")
|
logWriteStringErr(io.WriteString(rw, "data: "))
|
||||||
rw.Write(buf)
|
logWriteStringErr(rw.Write(buf))
|
||||||
io.WriteString(rw, "\n\n")
|
logWriteStringErr(io.WriteString(rw, "\n\n"))
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
}
|
}
|
||||||
id++
|
id++
|
||||||
|
@ -232,3 +240,9 @@ func LogStreamSSE(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logWriteStringErr(_ int, err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Caller(1).Msg("fail to write string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -47,7 +47,10 @@ func GetFeed(c *gin.Context) {
|
||||||
log.Debug().Msgf("sync begin: %s", user.Login)
|
log.Debug().Msgf("sync begin: %s", user.Login)
|
||||||
|
|
||||||
user.Synced = time.Now().Unix()
|
user.Synced = time.Now().Unix()
|
||||||
store_.UpdateUser(user)
|
if err := store_.UpdateUser(user); err != nil {
|
||||||
|
log.Error().Err(err).Msg("UpdateUser")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
config := ToConfig(c)
|
config := ToConfig(c)
|
||||||
|
|
||||||
|
@ -138,7 +141,7 @@ func PostToken(c *gin.Context) {
|
||||||
user := session.User(c)
|
user := session.User(c)
|
||||||
tokenString, err := token.New(token.UserToken, user.Login).Sign(user.Hash)
|
tokenString, err := token.New(token.UserToken, user.Login).Sign(user.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.String(http.StatusOK, tokenString)
|
c.String(http.StatusOK, tokenString)
|
||||||
|
@ -158,7 +161,7 @@ func DeleteToken(c *gin.Context) {
|
||||||
|
|
||||||
tokenString, err := token.New(token.UserToken, user.Login).Sign(user.Hash)
|
tokenString, err := token.New(token.UserToken, user.Login).Sign(user.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.String(http.StatusOK, tokenString)
|
c.String(http.StatusOK, tokenString)
|
||||||
|
|
|
@ -55,13 +55,13 @@ func SetLogLevel(c *gin.Context) {
|
||||||
LogLevel string `json:"log-level"`
|
LogLevel string `json:"log-level"`
|
||||||
}{}
|
}{}
|
||||||
if err := c.Bind(&logLevel); err != nil {
|
if err := c.Bind(&logLevel); err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lvl, err := zerolog.ParseLevel(logLevel.LogLevel)
|
lvl, err := zerolog.ParseLevel(logLevel.LogLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,9 @@ func (s *RPC) Next(c context.Context, filter rpc.Filter) (*rpc.Pipeline, error)
|
||||||
err = json.Unmarshal(task.Data, pipeline)
|
err = json.Unmarshal(task.Data, pipeline)
|
||||||
return pipeline, err
|
return pipeline, err
|
||||||
} else {
|
} else {
|
||||||
s.Done(c, task.ID, rpc.State{})
|
if err := s.Done(c, task.ID, rpc.State{}); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("mark task '%s' done failed", task.ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +153,9 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
|
||||||
Repo: *repo,
|
Repo: *repo,
|
||||||
Build: *build,
|
Build: *build,
|
||||||
})
|
})
|
||||||
s.pubsub.Publish(c, "topic/events", message)
|
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
|
||||||
|
log.Error().Err(err).Msg("can not publish proc list to")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -279,7 +283,9 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
|
||||||
Repo: *repo,
|
Repo: *repo,
|
||||||
Build: *build,
|
Build: *build,
|
||||||
})
|
})
|
||||||
s.pubsub.Publish(c, "topic/events", message)
|
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
|
||||||
|
log.Error().Err(err).Msg("can not publish proc list to")
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
_, err = shared.UpdateProcToStatusStarted(s.store, *proc, state)
|
_, err = shared.UpdateProcToStatusStarted(s.store, *proc, state)
|
||||||
|
@ -373,7 +379,9 @@ func isMultiPipeline(procs []*model.Proc) bool {
|
||||||
func (s *RPC) Log(c context.Context, id string, line *rpc.Line) error {
|
func (s *RPC) Log(c context.Context, id string, line *rpc.Line) error {
|
||||||
entry := new(logging.Entry)
|
entry := new(logging.Entry)
|
||||||
entry.Data, _ = json.Marshal(line)
|
entry.Data, _ = json.Marshal(line)
|
||||||
s.logger.Write(c, id, entry)
|
if err := s.logger.Write(c, id, entry); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("rpc server could not write to logger")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,9 +424,14 @@ func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *m
|
||||||
user, err := s.store.GetUser(repo.UserID)
|
user, err := s.store.GetUser(repo.UserID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if refresher, ok := s.remote.(remote.Refresher); ok {
|
if refresher, ok := s.remote.(remote.Refresher); ok {
|
||||||
ok, _ := refresher.Refresh(ctx, user)
|
ok, err := refresher.Refresh(ctx, user)
|
||||||
if ok {
|
if err != nil {
|
||||||
s.store.UpdateUser(user)
|
log.Error().Err(err).Msgf("grpc: refresh oauth token of user '%s' failed", user.Login)
|
||||||
|
} else if ok {
|
||||||
|
if err := s.store.UpdateUser(user); err != nil {
|
||||||
|
log.Error().Err(err).Msg("fail to save user to store after refresh oauth token")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uri := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, build.Number)
|
uri := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, build.Number)
|
||||||
|
@ -441,7 +454,9 @@ func (s *RPC) notify(c context.Context, repo *model.Repo, build *model.Build, pr
|
||||||
Repo: *repo,
|
Repo: *repo,
|
||||||
Build: *build,
|
Build: *build,
|
||||||
})
|
})
|
||||||
s.pubsub.Publish(c, "topic/events", message)
|
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
|
||||||
|
log.Error().Err(err).Msgf("grpc could not notify event: '%v'", message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFilterFunc(filter rpc.Filter) (queue.Filter, error) {
|
func createFilterFunc(filter rpc.Filter) (queue.Filter, error) {
|
||||||
|
|
|
@ -132,11 +132,15 @@ func (l *log) Snapshot(c context.Context, path string, w io.Writer) error {
|
||||||
return ErrNotFound
|
return ErrNotFound
|
||||||
}
|
}
|
||||||
s.Lock()
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
for _, entry := range s.list {
|
for _, entry := range s.list {
|
||||||
w.Write(entry.Data)
|
if _, err := w.Write(entry.Data); err != nil {
|
||||||
w.Write(cr)
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write(cr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.Unlock()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLogging(t *testing.T) {
|
func TestLogging(t *testing.T) {
|
||||||
|
@ -22,27 +24,27 @@ func TestLogging(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
logger := New()
|
logger := New()
|
||||||
logger.Open(ctx, testPath)
|
assert.NoError(t, logger.Open(ctx, testPath))
|
||||||
go func() {
|
go func() {
|
||||||
logger.Tail(ctx, testPath, func(entry ...*Entry) { wg.Done() })
|
assert.NoError(t, logger.Tail(ctx, testPath, func(entry ...*Entry) { wg.Done() }))
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
logger.Tail(ctx, testPath, func(entry ...*Entry) { wg.Done() })
|
assert.NoError(t, logger.Tail(ctx, testPath, func(entry ...*Entry) { wg.Done() }))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-time.After(500 * time.Millisecond)
|
<-time.After(500 * time.Millisecond)
|
||||||
|
|
||||||
wg.Add(4)
|
wg.Add(4)
|
||||||
go func() {
|
go func() {
|
||||||
logger.Write(ctx, testPath, testEntry)
|
assert.NoError(t, logger.Write(ctx, testPath, testEntry))
|
||||||
logger.Write(ctx, testPath, testEntry)
|
assert.NoError(t, logger.Write(ctx, testPath, testEntry))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
logger.Tail(ctx, testPath, func(entry ...*Entry) { wg.Done() })
|
assert.NoError(t, logger.Tail(ctx, testPath, func(entry ...*Entry) { wg.Done() }))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-time.After(500 * time.Millisecond)
|
<-time.After(500 * time.Millisecond)
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPubsub(t *testing.T) {
|
func TestPubsub(t *testing.T) {
|
||||||
|
@ -22,12 +24,12 @@ func TestPubsub(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
broker := New()
|
broker := New()
|
||||||
broker.Create(ctx, testTopic)
|
assert.NoError(t, broker.Create(ctx, testTopic))
|
||||||
go func() {
|
go func() {
|
||||||
broker.Subscribe(ctx, testTopic, func(message Message) { wg.Done() })
|
assert.NoError(t, broker.Subscribe(ctx, testTopic, func(message Message) { wg.Done() }))
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
broker.Subscribe(ctx, testTopic, func(message Message) { wg.Done() })
|
assert.NoError(t, broker.Subscribe(ctx, testTopic, func(message Message) { wg.Done() }))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-time.After(500 * time.Millisecond)
|
<-time.After(500 * time.Millisecond)
|
||||||
|
@ -38,7 +40,7 @@ func TestPubsub(t *testing.T) {
|
||||||
|
|
||||||
wg.Add(2)
|
wg.Add(2)
|
||||||
go func() {
|
go func() {
|
||||||
broker.Publish(ctx, testTopic, testMessage)
|
assert.NoError(t, broker.Publish(ctx, testTopic, testMessage))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
@ -80,9 +82,9 @@ func TestSubscriptionClosed(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
broker := New()
|
broker := New()
|
||||||
broker.Create(context.Background(), testTopic)
|
assert.NoError(t, broker.Create(context.Background(), testTopic))
|
||||||
go func() {
|
go func() {
|
||||||
broker.Subscribe(context.Background(), testTopic, testCallback)
|
assert.NoError(t, broker.Subscribe(context.Background(), testTopic, testCallback))
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ func TestSubscriptionClosed(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
broker.Remove(context.Background(), testTopic)
|
assert.NoError(t, broker.Remove(context.Background(), testTopic))
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
if _, ok := broker.(*publisher).topics[testTopic]; ok {
|
if _, ok := broker.(*publisher).topics[testTopic]; ok {
|
||||||
|
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var noContext = context.Background()
|
var noContext = context.Background()
|
||||||
|
@ -14,7 +16,7 @@ func TestFifo(t *testing.T) {
|
||||||
want := &Task{ID: "1"}
|
want := &Task{ID: "1"}
|
||||||
|
|
||||||
q := New()
|
q := New()
|
||||||
q.Push(noContext, want)
|
assert.NoError(t, q.Push(noContext, want))
|
||||||
info := q.Info(noContext)
|
info := q.Info(noContext)
|
||||||
if len(info.Pending) != 1 {
|
if len(info.Pending) != 1 {
|
||||||
t.Errorf("expect task in pending queue")
|
t.Errorf("expect task in pending queue")
|
||||||
|
@ -37,7 +39,7 @@ func TestFifo(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
q.Done(noContext, got.ID, StatusSuccess)
|
assert.NoError(t, q.Done(noContext, got.ID, StatusSuccess))
|
||||||
info = q.Info(noContext)
|
info = q.Info(noContext)
|
||||||
if len(info.Pending) != 0 {
|
if len(info.Pending) != 0 {
|
||||||
t.Errorf("expect task removed from pending queue")
|
t.Errorf("expect task removed from pending queue")
|
||||||
|
@ -54,7 +56,7 @@ func TestFifoExpire(t *testing.T) {
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.extension = 0
|
q.extension = 0
|
||||||
q.Push(noContext, want)
|
assert.NoError(t, q.Push(noContext, want))
|
||||||
info := q.Info(noContext)
|
info := q.Info(noContext)
|
||||||
if len(info.Pending) != 1 {
|
if len(info.Pending) != 1 {
|
||||||
t.Errorf("expect task in pending queue")
|
t.Errorf("expect task in pending queue")
|
||||||
|
@ -78,7 +80,7 @@ func TestFifoWait(t *testing.T) {
|
||||||
want := &Task{ID: "1"}
|
want := &Task{ID: "1"}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.Push(noContext, want)
|
assert.NoError(t, q.Push(noContext, want))
|
||||||
|
|
||||||
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
||||||
if got != want {
|
if got != want {
|
||||||
|
@ -89,12 +91,12 @@ func TestFifoWait(t *testing.T) {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
q.Wait(noContext, got.ID)
|
assert.NoError(t, q.Wait(noContext, got.ID))
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-time.After(time.Millisecond)
|
<-time.After(time.Millisecond)
|
||||||
q.Done(noContext, got.ID, StatusSuccess)
|
assert.NoError(t, q.Done(noContext, got.ID, StatusSuccess))
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +104,7 @@ func TestFifoEvict(t *testing.T) {
|
||||||
t1 := &Task{ID: "1"}
|
t1 := &Task{ID: "1"}
|
||||||
|
|
||||||
q := New()
|
q := New()
|
||||||
q.Push(noContext, t1)
|
assert.NoError(t, q.Push(noContext, t1))
|
||||||
info := q.Info(noContext)
|
info := q.Info(noContext)
|
||||||
if len(info.Pending) != 1 {
|
if len(info.Pending) != 1 {
|
||||||
t.Errorf("expect task in pending queue")
|
t.Errorf("expect task in pending queue")
|
||||||
|
@ -131,7 +133,7 @@ func TestFifoDependencies(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.PushAtOnce(noContext, []*Task{task2, task1})
|
assert.NoError(t, q.PushAtOnce(noContext, []*Task{task2, task1}))
|
||||||
|
|
||||||
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
||||||
if got != task1 {
|
if got != task1 {
|
||||||
|
@ -139,7 +141,7 @@ func TestFifoDependencies(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
q.Done(noContext, got.ID, StatusSuccess)
|
assert.NoError(t, q.Done(noContext, got.ID, StatusSuccess))
|
||||||
|
|
||||||
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
||||||
if got != task2 {
|
if got != task2 {
|
||||||
|
@ -167,7 +169,7 @@ func TestFifoErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.PushAtOnce(noContext, []*Task{task2, task3, task1})
|
assert.NoError(t, q.PushAtOnce(noContext, []*Task{task2, task3, task1}))
|
||||||
|
|
||||||
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
||||||
if got != task1 {
|
if got != task1 {
|
||||||
|
@ -175,7 +177,7 @@ func TestFifoErrors(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error"))
|
assert.NoError(t, q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error")))
|
||||||
|
|
||||||
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
||||||
if got != task2 {
|
if got != task2 {
|
||||||
|
@ -216,7 +218,7 @@ func TestFifoErrors2(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.PushAtOnce(noContext, []*Task{task2, task3, task1})
|
assert.NoError(t, q.PushAtOnce(noContext, []*Task{task2, task3, task1}))
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
||||||
|
@ -226,10 +228,10 @@ func TestFifoErrors2(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if got != task1 {
|
if got != task1 {
|
||||||
q.Done(noContext, got.ID, StatusSuccess)
|
assert.NoError(t, q.Done(noContext, got.ID, StatusSuccess))
|
||||||
}
|
}
|
||||||
if got != task2 {
|
if got != task2 {
|
||||||
q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error"))
|
assert.NoError(t, q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +265,7 @@ func TestFifoErrorsMultiThread(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.PushAtOnce(noContext, []*Task{task2, task3, task1})
|
assert.NoError(t, q.PushAtOnce(noContext, []*Task{task2, task3, task1}))
|
||||||
|
|
||||||
obtainedWorkCh := make(chan *Task)
|
obtainedWorkCh := make(chan *Task)
|
||||||
|
|
||||||
|
@ -291,7 +293,7 @@ func TestFifoErrorsMultiThread(t *testing.T) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
task1Processed = true
|
task1Processed = true
|
||||||
q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error"))
|
assert.NoError(t, q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error")))
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
fmt.Printf("Worker spawned\n")
|
fmt.Printf("Worker spawned\n")
|
||||||
|
@ -306,7 +308,7 @@ func TestFifoErrorsMultiThread(t *testing.T) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
task2Processed = true
|
task2Processed = true
|
||||||
q.Done(noContext, got.ID, StatusSuccess)
|
assert.NoError(t, q.Done(noContext, got.ID, StatusSuccess))
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
fmt.Printf("Worker spawned\n")
|
fmt.Printf("Worker spawned\n")
|
||||||
|
@ -356,14 +358,14 @@ func TestFifoTransitiveErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.PushAtOnce(noContext, []*Task{task2, task3, task1})
|
assert.NoError(t, q.PushAtOnce(noContext, []*Task{task2, task3, task1}))
|
||||||
|
|
||||||
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
||||||
if got != task1 {
|
if got != task1 {
|
||||||
t.Errorf("expect task1 returned from queue as task2 depends on it")
|
t.Errorf("expect task1 returned from queue as task2 depends on it")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error"))
|
assert.NoError(t, q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error")))
|
||||||
|
|
||||||
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
||||||
if got != task2 {
|
if got != task2 {
|
||||||
|
@ -374,7 +376,7 @@ func TestFifoTransitiveErrors(t *testing.T) {
|
||||||
t.Errorf("expect task2 should not run, since task1 failed")
|
t.Errorf("expect task2 should not run, since task1 failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
q.Done(noContext, got.ID, StatusSkipped)
|
assert.NoError(t, q.Done(noContext, got.ID, StatusSkipped))
|
||||||
|
|
||||||
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
||||||
if got != task3 {
|
if got != task3 {
|
||||||
|
@ -406,12 +408,12 @@ func TestFifoCancel(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.PushAtOnce(noContext, []*Task{task2, task3, task1})
|
assert.NoError(t, q.PushAtOnce(noContext, []*Task{task2, task3, task1}))
|
||||||
|
|
||||||
_, _ = q.Poll(noContext, func(*Task) bool { return true })
|
_, _ = q.Poll(noContext, func(*Task) bool { return true })
|
||||||
q.Error(noContext, task1.ID, fmt.Errorf("cancelled"))
|
assert.NoError(t, q.Error(noContext, task1.ID, fmt.Errorf("cancelled")))
|
||||||
q.Error(noContext, task2.ID, fmt.Errorf("cancelled"))
|
assert.NoError(t, q.Error(noContext, task2.ID, fmt.Errorf("cancelled")))
|
||||||
q.Error(noContext, task3.ID, fmt.Errorf("cancelled"))
|
assert.NoError(t, q.Error(noContext, task3.ID, fmt.Errorf("cancelled")))
|
||||||
|
|
||||||
info := q.Info(noContext)
|
info := q.Info(noContext)
|
||||||
if len(info.Pending) != 0 {
|
if len(info.Pending) != 0 {
|
||||||
|
@ -435,7 +437,7 @@ func TestFifoPause(t *testing.T) {
|
||||||
|
|
||||||
q.Pause()
|
q.Pause()
|
||||||
t0 := time.Now()
|
t0 := time.Now()
|
||||||
q.Push(noContext, task1)
|
assert.NoError(t, q.Push(noContext, task1))
|
||||||
time.Sleep(20 * time.Millisecond)
|
time.Sleep(20 * time.Millisecond)
|
||||||
q.Resume()
|
q.Resume()
|
||||||
|
|
||||||
|
@ -447,7 +449,7 @@ func TestFifoPause(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
q.Pause()
|
q.Pause()
|
||||||
q.Push(noContext, task1)
|
assert.NoError(t, q.Push(noContext, task1))
|
||||||
q.Resume()
|
q.Resume()
|
||||||
_, _ = q.Poll(noContext, func(*Task) bool { return true })
|
_, _ = q.Poll(noContext, func(*Task) bool { return true })
|
||||||
}
|
}
|
||||||
|
@ -459,7 +461,7 @@ func TestFifoPauseResume(t *testing.T) {
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.Pause()
|
q.Pause()
|
||||||
q.Push(noContext, task1)
|
assert.NoError(t, q.Push(noContext, task1))
|
||||||
q.Resume()
|
q.Resume()
|
||||||
|
|
||||||
_, _ = q.Poll(noContext, func(*Task) bool { return true })
|
_, _ = q.Poll(noContext, func(*Task) bool { return true })
|
||||||
|
@ -484,7 +486,7 @@ func TestWaitingVsPending(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
q := New().(*fifo)
|
q := New().(*fifo)
|
||||||
q.PushAtOnce(noContext, []*Task{task2, task3, task1})
|
assert.NoError(t, q.PushAtOnce(noContext, []*Task{task2, task3, task1}))
|
||||||
|
|
||||||
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
got, _ := q.Poll(noContext, func(*Task) bool { return true })
|
||||||
|
|
||||||
|
@ -493,7 +495,7 @@ func TestWaitingVsPending(t *testing.T) {
|
||||||
t.Errorf("2 should wait on deps")
|
t.Errorf("2 should wait on deps")
|
||||||
}
|
}
|
||||||
|
|
||||||
q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error"))
|
assert.NoError(t, q.Error(noContext, got.ID, fmt.Errorf("exitcode 1, there was an error")))
|
||||||
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
got, _ = q.Poll(noContext, func(*Task) bool { return true })
|
||||||
|
|
||||||
info = q.Info(noContext)
|
info = q.Info(noContext)
|
||||||
|
|
|
@ -18,6 +18,7 @@ package queue
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/model"
|
"github.com/woodpecker-ci/woodpecker/server/model"
|
||||||
|
@ -38,7 +39,9 @@ func WithTaskStore(q Queue, s model.TaskStore) Queue {
|
||||||
DepStatus: make(map[string]string),
|
DepStatus: make(map[string]string),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
q.PushAtOnce(context.Background(), toEnqueue)
|
if err := q.PushAtOnce(context.Background(), toEnqueue); err != nil {
|
||||||
|
log.Error().Err(err).Msg("PushAtOnce failed")
|
||||||
|
}
|
||||||
return &persistentQueue{q, s}
|
return &persistentQueue{q, s}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,35 +52,44 @@ type persistentQueue struct {
|
||||||
|
|
||||||
// Push pushes a task to the tail of this queue.
|
// Push pushes a task to the tail of this queue.
|
||||||
func (q *persistentQueue) Push(c context.Context, task *Task) error {
|
func (q *persistentQueue) Push(c context.Context, task *Task) error {
|
||||||
q.store.TaskInsert(&model.Task{
|
if err := q.store.TaskInsert(&model.Task{
|
||||||
ID: task.ID,
|
ID: task.ID,
|
||||||
Data: task.Data,
|
Data: task.Data,
|
||||||
Labels: task.Labels,
|
Labels: task.Labels,
|
||||||
Dependencies: task.Dependencies,
|
Dependencies: task.Dependencies,
|
||||||
RunOn: task.RunOn,
|
RunOn: task.RunOn,
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
err := q.Queue.Push(c, task)
|
err := q.Queue.Push(c, task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.store.TaskDelete(task.ID)
|
if err2 := q.store.TaskDelete(task.ID); err2 != nil {
|
||||||
|
err = errors.Wrapf(err, "delete task '%s' failed: %v", task.ID, err2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushAtOnce pushes multiple tasks to the tail of this queue.
|
// PushAtOnce pushes multiple tasks to the tail of this queue.
|
||||||
func (q *persistentQueue) PushAtOnce(c context.Context, tasks []*Task) error {
|
func (q *persistentQueue) PushAtOnce(c context.Context, tasks []*Task) error {
|
||||||
|
// TODO: invent store.NewSession who return context including a session and make TaskInsert & TaskDelete use it
|
||||||
for _, task := range tasks {
|
for _, task := range tasks {
|
||||||
q.store.TaskInsert(&model.Task{
|
if err := q.store.TaskInsert(&model.Task{
|
||||||
ID: task.ID,
|
ID: task.ID,
|
||||||
Data: task.Data,
|
Data: task.Data,
|
||||||
Labels: task.Labels,
|
Labels: task.Labels,
|
||||||
Dependencies: task.Dependencies,
|
Dependencies: task.Dependencies,
|
||||||
RunOn: task.RunOn,
|
RunOn: task.RunOn,
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err := q.Queue.PushAtOnce(c, tasks)
|
err := q.Queue.PushAtOnce(c, tasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
for _, task := range tasks {
|
for _, task := range tasks {
|
||||||
q.store.TaskDelete(task.ID)
|
if err := q.store.TaskDelete(task.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -101,18 +113,20 @@ func (q *persistentQueue) Poll(c context.Context, f Filter) (*Task, error) {
|
||||||
func (q *persistentQueue) Evict(c context.Context, id string) error {
|
func (q *persistentQueue) Evict(c context.Context, id string) error {
|
||||||
err := q.Queue.Evict(c, id)
|
err := q.Queue.Evict(c, id)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
q.store.TaskDelete(id)
|
return q.store.TaskDelete(id)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// EvictAtOnce removes a pending task from the queue.
|
// EvictAtOnce removes a pending task from the queue.
|
||||||
func (q *persistentQueue) EvictAtOnce(c context.Context, ids []string) error {
|
func (q *persistentQueue) EvictAtOnce(c context.Context, ids []string) error {
|
||||||
err := q.Queue.EvictAtOnce(c, ids)
|
if err := q.Queue.EvictAtOnce(c, ids); err != nil {
|
||||||
if err == nil {
|
|
||||||
for _, id := range ids {
|
|
||||||
q.store.TaskDelete(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
for _, id := range ids {
|
||||||
|
if err := q.store.TaskDelete(id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -239,7 +239,7 @@ func (c *config) Activate(ctx context.Context, u *model.User, r *model.Repo, lin
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.Deactivate(ctx, u, r, link)
|
_ = c.Deactivate(ctx, u, r, link)
|
||||||
|
|
||||||
return c.newClient(ctx, u).CreateHook(r.Owner, r.Name, &internal.Hook{
|
return c.newClient(ctx, u).CreateHook(r.Owner, r.Name, &internal.Hook{
|
||||||
Active: true,
|
Active: true,
|
||||||
|
|
|
@ -30,7 +30,6 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
get = "GET"
|
get = "GET"
|
||||||
put = "PUT"
|
|
||||||
post = "POST"
|
post = "POST"
|
||||||
del = "DELETE"
|
del = "DELETE"
|
||||||
)
|
)
|
||||||
|
@ -213,7 +212,7 @@ func (c *Client) do(rawurl, method string, in, out interface{}) (*string, error)
|
||||||
// error response.
|
// error response.
|
||||||
if resp.StatusCode > http.StatusPartialContent {
|
if resp.StatusCode > http.StatusPartialContent {
|
||||||
err := Error{}
|
err := Error{}
|
||||||
json.NewDecoder(resp.Body).Decode(&err)
|
_ = json.NewDecoder(resp.Body).Decode(&err)
|
||||||
err.Status = resp.StatusCode
|
err.Status = resp.StatusCode
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,6 @@ const (
|
||||||
hookPush = "repo:push"
|
hookPush = "repo:push"
|
||||||
hookPullCreated = "pullrequest:created"
|
hookPullCreated = "pullrequest:created"
|
||||||
hookPullUpdated = "pullrequest:updated"
|
hookPullUpdated = "pullrequest:updated"
|
||||||
|
|
||||||
changeBranch = "branch"
|
|
||||||
changeNamedBranch = "named_branch"
|
|
||||||
|
|
||||||
stateMerged = "MERGED"
|
|
||||||
stateDeclined = "DECLINED"
|
|
||||||
stateOpen = "OPEN"
|
stateOpen = "OPEN"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -100,11 +100,6 @@ func getDepot(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProjects(c *gin.Context) {
|
|
||||||
c.Header("Content-Type", "application/json;charset=UTF-8")
|
|
||||||
c.String(200, fakeProjectsPayload)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFile(c *gin.Context) {
|
func getFile(c *gin.Context) {
|
||||||
c.Header("Content-Type", "application/json;charset=UTF-8")
|
c.Header("Content-Type", "application/json;charset=UTF-8")
|
||||||
switch fmt.Sprintf("%s/%s/%s/%s", c.Param("gk"), c.Param("prj"), c.Param("ref"), c.Param("path")) {
|
switch fmt.Sprintf("%s/%s/%s/%s", c.Param("gk"), c.Param("prj"), c.Param("ref"), c.Param("path")) {
|
||||||
|
@ -273,23 +268,6 @@ const projectNotFoundPayload = `
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const fakeProjectsPayload = `
|
|
||||||
{
|
|
||||||
"code":0,
|
|
||||||
"data":{
|
|
||||||
"list":{
|
|
||||||
"owner_user_name":"demo1",
|
|
||||||
"name":"test1",
|
|
||||||
"icon":"/static/project_icon/scenery-5.png",
|
|
||||||
},
|
|
||||||
"page":1,
|
|
||||||
"pageSize":1,
|
|
||||||
"totalPage":1,
|
|
||||||
"totalRow":1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const fakeFilePayload = `
|
const fakeFilePayload = `
|
||||||
{
|
{
|
||||||
"code":0,
|
"code":0,
|
||||||
|
|
|
@ -76,7 +76,7 @@ func createRepoHook(c *gin.Context) {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
} `json:"config"`
|
} `json:"config"`
|
||||||
}{}
|
}{}
|
||||||
c.BindJSON(&in)
|
_ = c.BindJSON(&in)
|
||||||
if in.Type != "gitea" ||
|
if in.Type != "gitea" ||
|
||||||
in.Conf.Type != "json" ||
|
in.Conf.Type != "json" ||
|
||||||
in.Conf.URL != "http://localhost" {
|
in.Conf.URL != "http://localhost" {
|
||||||
|
|
|
@ -115,18 +115,6 @@ func convertPerm(from *github.Repository) *model.Perm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertTeamPerm is a helper function used to convert a GitHub organization
|
|
||||||
// permissions to the common Woodpecker permissions structure.
|
|
||||||
func convertTeamPerm(from *github.Membership) *model.Perm {
|
|
||||||
admin := false
|
|
||||||
if *from.Role == "admin" {
|
|
||||||
admin = true
|
|
||||||
}
|
|
||||||
return &model.Perm{
|
|
||||||
Admin: admin,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertRepoList is a helper function used to convert a GitHub repository
|
// convertRepoList is a helper function used to convert a GitHub repository
|
||||||
// list to the common Woodpecker repository structure.
|
// list to the common Woodpecker repository structure.
|
||||||
func convertRepoList(from []*github.Repository, private bool) []*model.Repo {
|
func convertRepoList(from []*github.Repository, private bool) []*model.Repo {
|
||||||
|
|
|
@ -270,9 +270,9 @@ func (c *client) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model
|
||||||
|
|
||||||
for i := 0; i < len(data); i++ {
|
for i := 0; i < len(data); i++ {
|
||||||
select {
|
select {
|
||||||
case err, _ := <-errc:
|
case err := <-errc:
|
||||||
errors = append(errors, err)
|
errors = append(errors, err)
|
||||||
case fileMeta, _ := <-fc:
|
case fileMeta := <-fc:
|
||||||
files = append(files, fileMeta)
|
files = append(files, fileMeta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +464,7 @@ func repoStatus(c context.Context, client *github.Client, r *model.Repo, b *mode
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var reDeploy = regexp.MustCompile(".+/deployments/(\\d+)")
|
var reDeploy = regexp.MustCompile(`.+/deployments/(\d+)`)
|
||||||
|
|
||||||
func deploymentStatus(ctx context.Context, client *github.Client, r *model.Repo, b *model.Build, link string) error {
|
func deploymentStatus(ctx context.Context, client *github.Client, r *model.Repo, b *model.Build, link string) error {
|
||||||
matches := reDeploy.FindStringSubmatch(b.Link)
|
matches := reDeploy.FindStringSubmatch(b.Link)
|
||||||
|
|
|
@ -150,11 +150,6 @@ var (
|
||||||
Token: "cfcd2084",
|
Token: "cfcd2084",
|
||||||
}
|
}
|
||||||
|
|
||||||
fakeUserNoRepos = &model.User{
|
|
||||||
Login: "octocat",
|
|
||||||
Token: "repos_not_found",
|
|
||||||
}
|
|
||||||
|
|
||||||
fakeRepo = &model.Repo{
|
fakeRepo = &model.Repo{
|
||||||
Owner: "octocat",
|
Owner: "octocat",
|
||||||
Name: "Hello-World",
|
Name: "Hello-World",
|
||||||
|
@ -170,8 +165,4 @@ var (
|
||||||
Name: "repo_not_found",
|
Name: "repo_not_found",
|
||||||
FullName: "test_name/repo_not_found",
|
FullName: "test_name/repo_not_found",
|
||||||
}
|
}
|
||||||
|
|
||||||
fakeBuild = &model.Build{
|
|
||||||
Commit: "9ecad50",
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -61,7 +61,7 @@ func createRepoHook(c *gin.Context) {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
} `json:"config"`
|
} `json:"config"`
|
||||||
}{}
|
}{}
|
||||||
c.BindJSON(&in)
|
_ = c.BindJSON(&in)
|
||||||
if in.Type != "gogs" ||
|
if in.Type != "gogs" ||
|
||||||
in.Conf.Type != "json" ||
|
in.Conf.Type != "json" ||
|
||||||
in.Conf.URL != "http://localhost" {
|
in.Conf.URL != "http://localhost" {
|
||||||
|
|
|
@ -104,7 +104,10 @@ func SetPerm() gin.HandlerFunc {
|
||||||
perm.Repo = repo.FullName
|
perm.Repo = repo.FullName
|
||||||
perm.UserID = user.ID
|
perm.UserID = user.ID
|
||||||
perm.Synced = time.Now().Unix()
|
perm.Synced = time.Now().Unix()
|
||||||
store_.PermUpsert(perm)
|
if err := store_.PermUpsert(perm); err != nil {
|
||||||
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ func MustAdmin() gin.HandlerFunc {
|
||||||
case user == nil:
|
case user == nil:
|
||||||
c.String(401, "User not authorized")
|
c.String(401, "User not authorized")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
case user.Admin == false:
|
case !user.Admin:
|
||||||
c.String(403, "User not authorized")
|
c.String(403, "User not authorized")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
default:
|
default:
|
||||||
|
@ -95,7 +95,7 @@ func MustRepoAdmin() gin.HandlerFunc {
|
||||||
case user == nil:
|
case user == nil:
|
||||||
c.String(401, "User not authorized")
|
c.String(401, "User not authorized")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
case perm.Admin == false:
|
case !perm.Admin:
|
||||||
c.String(403, "User not authorized")
|
c.String(403, "User not authorized")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -53,8 +53,10 @@ func Refresh(c *gin.Context) {
|
||||||
// attempts to refresh the access token. If the
|
// attempts to refresh the access token. If the
|
||||||
// token is refreshed, we must also persist to the
|
// token is refreshed, we must also persist to the
|
||||||
// database.
|
// database.
|
||||||
ok, _ = refresher.Refresh(c, user)
|
ok, err := refresher.Refresh(c, user)
|
||||||
if ok {
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("refresh oauth token of user '%s' failed", user.Login)
|
||||||
|
} else if ok {
|
||||||
err := store.FromContext(c).UpdateUser(user)
|
err := store.FromContext(c).UpdateUser(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// we only log the error at this time. not sure
|
// we only log the error at this time. not sure
|
||||||
|
|
|
@ -40,9 +40,8 @@ type Syncer struct {
|
||||||
// synchronized with the local datastore.
|
// synchronized with the local datastore.
|
||||||
type FilterFunc func(*model.Repo) bool
|
type FilterFunc func(*model.Repo) bool
|
||||||
|
|
||||||
// NamespaceFilter
|
|
||||||
func NamespaceFilter(namespaces map[string]bool) FilterFunc {
|
func NamespaceFilter(namespaces map[string]bool) FilterFunc {
|
||||||
if namespaces == nil || len(namespaces) == 0 {
|
if len(namespaces) == 0 {
|
||||||
return noopFilter
|
return noopFilter
|
||||||
}
|
}
|
||||||
return func(repo *model.Repo) bool {
|
return func(repo *model.Repo) bool {
|
||||||
|
|
|
@ -16,12 +16,13 @@ package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server"
|
"github.com/woodpecker-ci/woodpecker/server"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
|
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
|
||||||
"github.com/woodpecker-ci/woodpecker/shared/token"
|
"github.com/woodpecker-ci/woodpecker/shared/token"
|
||||||
|
@ -29,8 +30,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func WebConfig(c *gin.Context) {
|
func WebConfig(c *gin.Context) {
|
||||||
var err error
|
|
||||||
|
|
||||||
user := session.User(c)
|
user := session.User(c)
|
||||||
|
|
||||||
var csrf string
|
var csrf string
|
||||||
|
@ -65,10 +64,9 @@ func WebConfig(c *gin.Context) {
|
||||||
c.Header("Content-Type", "text/javascript; charset=utf-8")
|
c.Header("Content-Type", "text/javascript; charset=utf-8")
|
||||||
tmpl := template.Must(template.New("").Funcs(funcMap).Parse(configTemplate))
|
tmpl := template.Must(template.New("").Funcs(funcMap).Parse(configTemplate))
|
||||||
|
|
||||||
err = tmpl.Execute(c.Writer, configData)
|
if err := tmpl.Execute(c.Writer, configData); err != nil {
|
||||||
if err != nil {
|
log.Error().Err(err).Msgf("could not execute template")
|
||||||
fmt.Println(err)
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
c.AbortWithError(http.StatusInternalServerError, nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server/model"
|
"github.com/woodpecker-ci/woodpecker/server/model"
|
||||||
"github.com/woodpecker-ci/woodpecker/shared/token"
|
"github.com/woodpecker-ci/woodpecker/shared/token"
|
||||||
|
@ -67,8 +68,6 @@ func (w *website) Register(mux *gin.Engine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *website) handleIndex(rw http.ResponseWriter, r *http.Request) {
|
func (w *website) handleIndex(rw http.ResponseWriter, r *http.Request) {
|
||||||
rw.WriteHeader(200)
|
|
||||||
|
|
||||||
var csrf string
|
var csrf string
|
||||||
var user, _ = ToUser(r.Context())
|
var user, _ = ToUser(r.Context())
|
||||||
if user != nil {
|
if user != nil {
|
||||||
|
@ -89,7 +88,13 @@ func (w *website) handleIndex(rw http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
rw.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
rw.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
||||||
|
|
||||||
w.tmpl.Execute(rw, params)
|
if err := w.tmpl.Execute(rw, params); err != nil {
|
||||||
|
rw.WriteHeader(http.StatusInternalServerError)
|
||||||
|
log.Error().Err(err).Msg("execute template")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rw.WriteHeader(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupCache(h http.Handler) http.Handler {
|
func setupCache(h http.Handler) http.Handler {
|
||||||
|
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
|
@ -436,6 +436,7 @@ github.com/pelletier/go-toml
|
||||||
# github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d
|
# github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d
|
||||||
github.com/phayes/checkstyle
|
github.com/phayes/checkstyle
|
||||||
# github.com/pkg/errors v0.9.1
|
# github.com/pkg/errors v0.9.1
|
||||||
|
## explicit
|
||||||
github.com/pkg/errors
|
github.com/pkg/errors
|
||||||
# github.com/pmezard/go-difflib v1.0.0
|
# github.com/pmezard/go-difflib v1.0.0
|
||||||
github.com/pmezard/go-difflib/difflib
|
github.com/pmezard/go-difflib/difflib
|
||||||
|
|
Loading…
Reference in a new issue