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:
6543 2021-11-23 15:36:52 +01:00 committed by GitHub
parent f454371e56
commit fe31fb1e06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
59 changed files with 464 additions and 347 deletions

View file

@ -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

View file

@ -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")
} }

View file

@ -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

View file

@ -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
} }

View file

@ -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
}) })

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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 {

View file

@ -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.

View file

@ -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

View file

@ -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
View file

@ -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

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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 == "" {

View file

@ -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 {

View file

@ -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")

View file

@ -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

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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 {

View file

@ -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)
} }

View file

@ -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()
}() }()
} }

View file

@ -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
} }

View file

@ -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'}) {

View file

@ -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
} }

View file

@ -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")
}
} }

View file

@ -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) {

View file

@ -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(),
}) })
} }

View file

@ -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,26 +242,33 @@ 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 {
repo.Name = from.Name log.Error().Err(err).Msgf("get repo '%s/%s' from remote", repo.Owner, repo.Name)
repo.Owner = from.Owner c.AbortWithStatus(http.StatusInternalServerError)
repo.FullName = from.FullName return
repo.Avatar = from.Avatar }
repo.Link = from.Link repo.Name = from.Name
repo.Clone = from.Clone repo.Owner = from.Owner
repo.IsSCMPrivate = from.IsSCMPrivate repo.FullName = from.FullName
if repo.IsSCMPrivate != from.IsSCMPrivate { repo.Avatar = from.Avatar
repo.ResetVisibility() repo.Link = from.Link
} repo.Clone = from.Clone
store_.UpdateRepo(repo) repo.IsSCMPrivate = from.IsSCMPrivate
if repo.IsSCMPrivate != from.IsSCMPrivate {
repo.ResetVisibility()
}
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
} }

View file

@ -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")
}
}

View file

@ -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)

View file

@ -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
} }

View file

@ -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) {

View file

@ -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
} }

View file

@ -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)

View file

@ -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 {

View file

@ -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)

View file

@ -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 { return err
for _, id := range ids { }
q.store.TaskDelete(id) for _, id := range ids {
if err := q.store.TaskDelete(id); err != nil {
return err
} }
} }
return err return nil
} }

View file

@ -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,

View file

@ -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
} }

View file

@ -28,13 +28,7 @@ const (
hookPush = "repo:push" hookPush = "repo:push"
hookPullCreated = "pullrequest:created" hookPullCreated = "pullrequest:created"
hookPullUpdated = "pullrequest:updated" hookPullUpdated = "pullrequest:updated"
stateOpen = "OPEN"
changeBranch = "branch"
changeNamedBranch = "named_branch"
stateMerged = "MERGED"
stateDeclined = "DECLINED"
stateOpen = "OPEN"
) )
// parseHook parses a Bitbucket hook from an http.Request request and returns // parseHook parses a Bitbucket hook from an http.Request request and returns

View file

@ -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,

View file

@ -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" {

View file

@ -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 {

View file

@ -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)

View file

@ -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",
}
) )

View file

@ -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" {

View file

@ -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
}
} }
} }
} }

View file

@ -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:

View file

@ -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

View file

@ -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 {

View file

@ -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)
} }
} }

View file

@ -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
View file

@ -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