You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02: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:
		| @@ -8,7 +8,17 @@ linters: | ||||
|     - gofmt | ||||
|     - goimports | ||||
|     - govet | ||||
|     - deadcode | ||||
|     - gosimple | ||||
|     - typecheck | ||||
|     - errcheck | ||||
|     - bidichk | ||||
|  | ||||
| run: | ||||
|   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): | ||||
| 				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") | ||||
|  | ||||
| 		limitedPart := io.LimitReader(part, maxLogsUpload) | ||||
| 		logstream := rpc.NewLineWriter(r.client, work.ID, proc.Alias, secrets...) | ||||
| 		io.Copy(logstream, limitedPart) | ||||
| 		logStream := rpc.NewLineWriter(r.client, work.ID, proc.Alias, secrets...) | ||||
| 		if _, err := io.Copy(logStream, limitedPart); err != nil { | ||||
| 			log.Error().Err(err).Msg("copy limited logStream part") | ||||
| 		} | ||||
|  | ||||
| 		loglogger.Debug().Msg("log stream copied") | ||||
|  | ||||
| 		data, err := json.Marshal(logstream.Lines()) | ||||
| 		data, err := json.Marshal(logStream.Lines()) | ||||
| 		if err != nil { | ||||
| 			loglogger.Err(err).Msg("could not marshal logstream") | ||||
| 		} | ||||
|   | ||||
| @@ -78,7 +78,9 @@ func buildList(c *cli.Context) error { | ||||
| 		if status != "" && build.Status != status { | ||||
| 			continue | ||||
| 		} | ||||
| 		tmpl.Execute(os.Stdout, build) | ||||
| 		if err := tmpl.Execute(os.Stdout, build); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		count++ | ||||
| 	} | ||||
| 	return nil | ||||
|   | ||||
| @@ -44,7 +44,9 @@ func buildQueue(c *cli.Context) error { | ||||
| 	} | ||||
|  | ||||
| 	for _, build := range builds { | ||||
| 		tmpl.Execute(os.Stdout, build) | ||||
| 		if err := tmpl.Execute(os.Stdout, build); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -260,8 +260,7 @@ var defaultLogger = pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reade | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	logstream := NewLineWriter(proc.Alias) | ||||
| 	io.Copy(logstream, part) | ||||
|  | ||||
| 	return nil | ||||
| 	logStream := NewLineWriter(proc.Alias) | ||||
| 	_, err = io.Copy(logStream, part) | ||||
| 	return err | ||||
| }) | ||||
|   | ||||
| @@ -43,7 +43,7 @@ func lint(c *cli.Context) error { | ||||
| 		// check if it is a regular file (not dir) | ||||
| 		if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".yml") { | ||||
| 			fmt.Println("#", info.Name()) | ||||
| 			lintFile(path) | ||||
| 			_ = lintFile(path) // TODO: should we drop errors or store them and report back? | ||||
| 			fmt.Println("") | ||||
| 			return nil | ||||
| 		} | ||||
|   | ||||
| @@ -49,7 +49,9 @@ func registryList(c *cli.Context) error { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, registry := range list { | ||||
| 		tmpl.Execute(os.Stdout, registry) | ||||
| 		if err := tmpl.Execute(os.Stdout, registry); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -45,7 +45,9 @@ func repoList(c *cli.Context) error { | ||||
| 		if org != "" && org != repo.Owner { | ||||
| 			continue | ||||
| 		} | ||||
| 		tmpl.Execute(os.Stdout, repo) | ||||
| 		if err := tmpl.Execute(os.Stdout, repo); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -41,7 +41,9 @@ func repoSync(c *cli.Context) error { | ||||
| 		if org != "" && org != repo.Owner { | ||||
| 			continue | ||||
| 		} | ||||
| 		tmpl.Execute(os.Stdout, repo) | ||||
| 		if err := tmpl.Execute(os.Stdout, repo); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -50,7 +50,9 @@ func secretList(c *cli.Context) error { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, registry := range list { | ||||
| 		tmpl.Execute(os.Stdout, registry) | ||||
| 		if err := tmpl.Execute(os.Stdout, registry); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -36,7 +36,9 @@ func userList(c *cli.Context) error { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, user := range users { | ||||
| 		tmpl.Execute(os.Stdout, user) | ||||
| 		if err := tmpl.Execute(os.Stdout, user); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/urfave/cli/v2" | ||||
|  | ||||
| 	"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) { | ||||
| 	w.WriteHeader(200) | ||||
| 	w.Header().Add("Content-Type", "text/json") | ||||
| 	json.NewEncoder(w).Encode(versionResp{ | ||||
| 	_ = json.NewEncoder(w).Encode(versionResp{ | ||||
| 		Source:  "https://github.com/woodpecker-ci/woodpecker", | ||||
| 		Version: version.String(), | ||||
| 	}) | ||||
| @@ -59,7 +60,9 @@ func handleStats(w http.ResponseWriter, r *http.Request) { | ||||
| 		w.WriteHeader(500) | ||||
| 	} | ||||
| 	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 { | ||||
|   | ||||
| @@ -12,14 +12,6 @@ import ( | ||||
| 	"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 | ||||
| // an os interrupt signal is received. The callback function f is invoked | ||||
| // before cancellation. | ||||
|   | ||||
| @@ -19,19 +19,21 @@ import ( | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/joho/godotenv" | ||||
| 	_ "github.com/joho/godotenv/autoload" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/urfave/cli/v2" | ||||
|  | ||||
| 	"github.com/woodpecker-ci/woodpecker/version" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	godotenv.Load(".env") | ||||
| 	if err := godotenv.Load(".env"); err != nil { | ||||
| 		log.Error().Err(err).Msg("load godotenv failed") | ||||
| 	} | ||||
| 	app := cli.NewApp() | ||||
| 	app.Name = "woodpecker-server" | ||||
| 	app.Version = version.String() | ||||
| 	app.Usage = "woodpecker server" | ||||
| 	app.Action = loop | ||||
| 	app.Action = run | ||||
| 	app.Flags = flags | ||||
| 	app.Before = before | ||||
|  | ||||
|   | ||||
| @@ -49,7 +49,7 @@ import ( | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/store" | ||||
| ) | ||||
|  | ||||
| func loop(c *cli.Context) error { | ||||
| func run(c *cli.Context) error { | ||||
|  | ||||
| 	if c.Bool("pretty") { | ||||
| 		log.Logger = log.Output( | ||||
| @@ -224,7 +224,9 @@ func loop(c *cli.Context) error { | ||||
| 	} | ||||
|  | ||||
| 	dir := cacheDir() | ||||
| 	os.MkdirAll(dir, 0700) | ||||
| 	if err := os.MkdirAll(dir, 0700); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	manager := &autocert.Manager{ | ||||
| 		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.Logs = logging.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.Secrets = setupSecretService(c, 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/morikuni/aec v1.0.0 // indirect | ||||
| 	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/rs/zerolog v1.25.0 | ||||
| 	github.com/stretchr/objx v0.3.0 // indirect | ||||
|   | ||||
| @@ -79,7 +79,7 @@ func toHostConfig(proc *backend.Step) *container.HostConfig { | ||||
| 	} | ||||
| 	config.Tmpfs = map[string]string{} | ||||
| 	for _, path := range proc.Tmpfs { | ||||
| 		if strings.Index(path, ":") == -1 { | ||||
| 		if !strings.Contains(path, ":") { | ||||
| 			config.Tmpfs[path] = "" | ||||
| 			continue | ||||
| 		} | ||||
| @@ -89,9 +89,6 @@ func toHostConfig(proc *backend.Step) *container.HostConfig { | ||||
| 		} | ||||
| 		config.Tmpfs[parts[0]] = parts[1] | ||||
| 	} | ||||
| 	// if proc.OomKillDisable { | ||||
| 	// 	config.OomKillDisable = &proc.OomKillDisable | ||||
| 	// } | ||||
|  | ||||
| 	return config | ||||
| } | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import ( | ||||
| 	"github.com/moby/moby/pkg/jsonmessage" | ||||
| 	"github.com/moby/moby/pkg/stdcopy" | ||||
| 	"github.com/moby/term" | ||||
| 	"github.com/rs/zerolog/log" | ||||
|  | ||||
| 	"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() | ||||
|  | ||||
| 			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 | ||||
| 		if perr != nil && proc.AuthConfig.Password != "" { | ||||
| @@ -98,7 +101,9 @@ func (e *engine) Exec(ctx context.Context, proc *backend.Step) error { | ||||
| 		} | ||||
| 		defer responseBody.Close() | ||||
| 		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) | ||||
| 	} | ||||
| @@ -162,11 +167,12 @@ func (e *engine) Tail(ctx context.Context, proc *backend.Step) (io.ReadCloser, e | ||||
| 	} | ||||
| 	rc, wc := io.Pipe() | ||||
|  | ||||
| 	// de multiplex 'logs' who contains two streams, previously multiplexed together using StdWriter | ||||
| 	go func() { | ||||
| 		stdcopy.StdCopy(wc, wc, logs) | ||||
| 		logs.Close() | ||||
| 		wc.Close() | ||||
| 		rc.Close() | ||||
| 		_, _ = stdcopy.StdCopy(wc, wc, logs) | ||||
| 		_ = logs.Close() | ||||
| 		_ = wc.Close() | ||||
| 		_ = rc.Close() | ||||
| 	}() | ||||
| 	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 { | ||||
| 	for _, stage := range conf.Stages { | ||||
| 		for _, step := range stage.Steps { | ||||
| 			e.client.ContainerKill(noContext, step.Name, "9") | ||||
| 			e.client.ContainerRemove(noContext, step.Name, removeOpts) | ||||
| 			if err := e.client.ContainerKill(noContext, step.Name, "9"); err != nil { | ||||
| 				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 { | ||||
| 		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 { | ||||
| 		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 | ||||
| } | ||||
|   | ||||
| @@ -233,7 +233,7 @@ func (m *Metadata) EnvironDrone() map[string]string { | ||||
| 	return params | ||||
| } | ||||
|  | ||||
| var pullRegexp = regexp.MustCompile("\\d+") | ||||
| var pullRegexp = regexp.MustCompile(`\d+`) | ||||
|  | ||||
| func (m *Metadata) SetPlatform(platform string) { | ||||
| 	if platform == "" { | ||||
|   | ||||
| @@ -5,6 +5,8 @@ import ( | ||||
| 	"path" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
|  | ||||
| 	"github.com/woodpecker-ci/woodpecker/pipeline/backend" | ||||
| 	"github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml" | ||||
| ) | ||||
| @@ -67,12 +69,14 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section | ||||
| 		detached = true | ||||
| 	} | ||||
|  | ||||
| 	if detached == false || len(container.Commands) != 0 { | ||||
| 	if !detached || len(container.Commands) != 0 { | ||||
| 		workingdir = path.Join(c.base, c.path) | ||||
| 	} | ||||
|  | ||||
| 	if detached == false { | ||||
| 		paramsToEnv(container.Vargs, environment) | ||||
| 	if !detached { | ||||
| 		if err := paramsToEnv(container.Vargs, environment); err != nil { | ||||
| 			log.Error().Err(err).Msg("paramsToEnv") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(container.Commands) != 0 { | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/kr/pretty" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestParamsToEnv(t *testing.T) { | ||||
| @@ -28,7 +29,7 @@ func TestParamsToEnv(t *testing.T) { | ||||
| 		"PLUGIN_COMPLEX": `[{"name":"Jack"},{"name":"Jill"}]`, | ||||
| 	} | ||||
| 	got := map[string]string{} | ||||
| 	paramsToEnv(from, got) | ||||
| 	assert.NoError(t, paramsToEnv(from, got)) | ||||
|  | ||||
| 	if !reflect.DeepEqual(want, got) { | ||||
| 		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{} | ||||
|  | ||||
| 	unmarshal(&out1) | ||||
| 	unmarshal(&out2) | ||||
| 	_ = unmarshal(&out1) // it contains include and exclude statement | ||||
| 	_ = unmarshal(&out2) // it contains no include/exclude statement, assume include as default | ||||
|  | ||||
| 	c.Include = out1.Include | ||||
| 	c.Exclude = out1.Exclude | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package yaml | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"gopkg.in/yaml.v3" | ||||
|  | ||||
| 	"github.com/woodpecker-ci/woodpecker/pipeline/frontend" | ||||
| @@ -142,7 +143,7 @@ func TestConstraint(t *testing.T) { | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, test := range testdata { | ||||
| 		c := parseConstraint(test.conf) | ||||
| 		c := parseConstraint(t, test.conf) | ||||
| 		got, want := c.Match(test.with), test.want | ||||
| 		if got != 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 { | ||||
| 		c := parseConstraintPath(test.conf) | ||||
| 		c := parseConstraintPath(t, test.conf) | ||||
| 		got, want := c.Match(test.with, test.message), test.want | ||||
| 		if got != want { | ||||
| 			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 { | ||||
| 		c := parseConstraintMap(test.conf) | ||||
| 		c := parseConstraintMap(t, test.conf) | ||||
| 		got, want := c.Match(test.with), test.want | ||||
| 		if got != 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 { | ||||
| 		c := parseConstraints(test.conf) | ||||
| 		c := parseConstraints(t, test.conf) | ||||
| 		got, want := c.Match(test.with), test.want | ||||
| 		if got != 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{} | ||||
| 	yaml.Unmarshal([]byte(s), c) | ||||
| 	assert.NoError(t, yaml.Unmarshal([]byte(s), c)) | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| func parseConstraint(s string) *Constraint { | ||||
| func parseConstraint(t *testing.T, s string) *Constraint { | ||||
| 	c := &Constraint{} | ||||
| 	yaml.Unmarshal([]byte(s), c) | ||||
| 	assert.NoError(t, yaml.Unmarshal([]byte(s), c)) | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| func parseConstraintMap(s string) *ConstraintMap { | ||||
| func parseConstraintMap(t *testing.T, s string) *ConstraintMap { | ||||
| 	c := &ConstraintMap{} | ||||
| 	yaml.Unmarshal([]byte(s), c) | ||||
| 	assert.NoError(t, yaml.Unmarshal([]byte(s), c)) | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| func parseConstraintPath(s string) *ConstraintPath { | ||||
| func parseConstraintPath(t *testing.T, s string) *ConstraintPath { | ||||
| 	c := &ConstraintPath{} | ||||
| 	yaml.Unmarshal([]byte(s), c) | ||||
| 	assert.NoError(t, yaml.Unmarshal([]byte(s), c)) | ||||
| 	return c | ||||
| } | ||||
|   | ||||
| @@ -48,7 +48,7 @@ func (l *Linter) lint(containers []*yaml.Container, block uint8) error { | ||||
| 		if err := l.lintImage(container); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if l.trusted == false { | ||||
| 		if !l.trusted { | ||||
| 			if err := l.lintTrusted(container); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|   | ||||
| @@ -14,7 +14,9 @@ type BoolTrue struct { | ||||
| // UnmarshalYAML implements custom Yaml unmarshaling. | ||||
| func (b *BoolTrue) UnmarshalYAML(value *yaml.Node) error { | ||||
| 	var s string | ||||
| 	value.Decode(&s) | ||||
| 	if err := value.Decode(&s); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	v, err := strconv.ParseBool(s) | ||||
| 	if err == nil { | ||||
|   | ||||
| @@ -16,7 +16,7 @@ type StructStringorInt struct { | ||||
| func TestStringorIntYaml(t *testing.T) { | ||||
| 	for _, str := range []string{`{foo: 10}`, `{foo: "10"}`} { | ||||
| 		s := StructStringorInt{} | ||||
| 		yaml.Unmarshal([]byte(str), &s) | ||||
| 		assert.NoError(t, yaml.Unmarshal([]byte(str), &s)) | ||||
|  | ||||
| 		assert.Equal(t, StringorInt(10), s.Foo) | ||||
|  | ||||
| @@ -24,7 +24,7 @@ func TestStringorIntYaml(t *testing.T) { | ||||
| 		assert.Nil(t, err) | ||||
|  | ||||
| 		s2 := StructStringorInt{} | ||||
| 		yaml.Unmarshal(d, &s2) | ||||
| 		assert.NoError(t, yaml.Unmarshal(d, &s2)) | ||||
|  | ||||
| 		assert.Equal(t, StringorInt(10), s2.Foo) | ||||
| 	} | ||||
| @@ -38,7 +38,7 @@ func TestStringorsliceYaml(t *testing.T) { | ||||
| 	str := `{foo: [bar, baz]}` | ||||
|  | ||||
| 	s := StructStringorslice{} | ||||
| 	yaml.Unmarshal([]byte(str), &s) | ||||
| 	assert.NoError(t, yaml.Unmarshal([]byte(str), &s)) | ||||
|  | ||||
| 	assert.Equal(t, Stringorslice{"bar", "baz"}, s.Foo) | ||||
|  | ||||
| @@ -46,7 +46,7 @@ func TestStringorsliceYaml(t *testing.T) { | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	s2 := StructStringorslice{} | ||||
| 	yaml.Unmarshal(d, &s2) | ||||
| 	assert.NoError(t, yaml.Unmarshal(d, &s2)) | ||||
|  | ||||
| 	assert.Equal(t, Stringorslice{"bar", "baz"}, s2.Foo) | ||||
| } | ||||
| @@ -60,7 +60,7 @@ func TestSliceOrMapYaml(t *testing.T) { | ||||
| 	str := `{foos: [bar=baz, far=faz]}` | ||||
|  | ||||
| 	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) | ||||
|  | ||||
| @@ -68,7 +68,7 @@ func TestSliceOrMapYaml(t *testing.T) { | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	s2 := StructSliceorMap{} | ||||
| 	yaml.Unmarshal(d, &s2) | ||||
| 	assert.NoError(t, yaml.Unmarshal(d, &s2)) | ||||
|  | ||||
| 	assert.Equal(t, SliceorMap{"bar": "baz", "far": "faz"}, s2.Foos) | ||||
| } | ||||
| @@ -95,7 +95,7 @@ func TestStr2SliceOrMapPtrMap(t *testing.T) { | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	s2 := map[string]*StructSliceorMap{} | ||||
| 	yaml.Unmarshal(d, &s2) | ||||
| 	assert.NoError(t, yaml.Unmarshal(d, &s2)) | ||||
|  | ||||
| 	assert.Equal(t, s, s2) | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"context" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"golang.org/x/sync/errgroup" | ||||
|  | ||||
| 	"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. | ||||
| func (r *Runtime) Run() error { | ||||
| 	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() | ||||
| @@ -105,9 +108,9 @@ func (r *Runtime) execAll(procs []*backend.Step) <-chan error { | ||||
|  | ||||
| func (r *Runtime) exec(proc *backend.Step) error { | ||||
| 	switch { | ||||
| 	case r.err != nil && proc.OnFailure == false: | ||||
| 	case r.err != nil && !proc.OnFailure: | ||||
| 		return nil | ||||
| 	case r.err == nil && proc.OnSuccess == false: | ||||
| 	case r.err == nil && !proc.OnSuccess: | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| @@ -135,8 +138,10 @@ func (r *Runtime) exec(proc *backend.Step) error { | ||||
| 		} | ||||
|  | ||||
| 		go func() { | ||||
| 			r.logger.Log(proc, multipart.New(rc)) | ||||
| 			rc.Close() | ||||
| 			if err := r.logger.Log(proc, multipart.New(rc)); err != nil { | ||||
| 				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.Timeout = res.GetPipeline().GetTimeout() | ||||
| 	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 | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,8 @@ import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| ) | ||||
|  | ||||
| // 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()), | ||||
| 		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++ | ||||
|  | ||||
| 	// for _, part := range bytes.Split(p, []byte{'\n'}) { | ||||
|   | ||||
| @@ -19,7 +19,6 @@ package api | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| @@ -42,7 +41,7 @@ func GetBuilds(c *gin.Context) { | ||||
| 	repo := session.Repo(c) | ||||
| 	page, err := strconv.Atoi(c.DefaultQuery("page", "1")) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -64,13 +63,13 @@ func GetBuild(c *gin.Context) { | ||||
| 	repo := session.Repo(c) | ||||
| 	num, err := strconv.ParseInt(c.Param("number"), 10, 64) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	build, err := store_.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
| 	files, _ := store_.FileList(build) | ||||
| @@ -109,26 +108,28 @@ func GetBuildLogs(c *gin.Context) { | ||||
|  | ||||
| 	build, err := store_.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	proc, err := store_.ProcChild(build, ppid, name) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	rc, err := store_.LogFind(proc) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	defer rc.Close() | ||||
|  | ||||
| 	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) { | ||||
| @@ -142,26 +143,28 @@ func GetProcLogs(c *gin.Context) { | ||||
|  | ||||
| 	build, err := store_.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	proc, err := store_.ProcFind(build, pid) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	rc, err := store_.LogFind(proc) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	defer rc.Close() | ||||
|  | ||||
| 	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 | ||||
| @@ -203,9 +206,19 @@ func DeleteBuild(c *gin.Context) { | ||||
| 			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) | ||||
| 	server.Config.Services.Queue.ErrorAtOnce(context.Background(), procToCancel, queue.ErrCancel) | ||||
|  | ||||
| 	if err := server.Config.Services.Queue.EvictAtOnce(c, procToEvict); err != nil { | ||||
| 		_ = 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 | ||||
| 	// 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) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(500, err) | ||||
| 		_ = c.AbortWithError(500, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -234,11 +247,13 @@ func DeleteBuild(c *gin.Context) { | ||||
| 	if build.Status == model.StatusPending { | ||||
| 		procs, err = store_.ProcList(killedBuild) | ||||
| 		if err != nil { | ||||
| 			c.AbortWithError(404, err) | ||||
| 			_ = c.AbortWithError(404, err) | ||||
| 			return | ||||
| 		} | ||||
| 		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, "") | ||||
| @@ -255,7 +270,7 @@ func PostApproval(c *gin.Context) { | ||||
|  | ||||
| 	build, err := store_.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
| 	if build.Status != model.StatusBlocked { | ||||
| @@ -267,7 +282,7 @@ func PostApproval(c *gin.Context) { | ||||
| 	configs, err := server.Config.Storage.Config.ConfigsForBuild(build.ID) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to get build config for %s. %s", repo.FullName, err) | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -347,8 +362,12 @@ func PostApproval(c *gin.Context) { | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	publishToTopic(c, build, repo, model.Enqueued) | ||||
| 	queueBuild(build, repo, buildItems) | ||||
| 	if err := publishToTopic(c, build, repo, model.Enqueued); err != nil { | ||||
| 		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) { | ||||
| @@ -363,7 +382,7 @@ func PostDecline(c *gin.Context) { | ||||
|  | ||||
| 	build, err := store_.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
| 	if build.Status != model.StatusBlocked { | ||||
| @@ -402,21 +421,21 @@ func PostBuild(c *gin.Context) { | ||||
|  | ||||
| 	num, err := strconv.ParseInt(c.Param("number"), 10, 64) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	user, err := store_.GetUser(repo.UserID) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to find repo owner %s. %s", repo.FullName, err) | ||||
| 		c.AbortWithError(500, err) | ||||
| 		_ = c.AbortWithError(500, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	build, err := store_.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to get build %d. %s", num, err) | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -431,9 +450,13 @@ func PostBuild(c *gin.Context) { | ||||
| 	// may be stale. Therefore, we should refresh prior to dispatching | ||||
| 	// the job. | ||||
| 	if refresher, ok := remote_.(remote.Refresher); ok { | ||||
| 		ok, _ := refresher.Refresh(c, user) | ||||
| 		if ok { | ||||
| 			store_.UpdateUser(user) | ||||
| 		ok, err := refresher.Refresh(c, user) | ||||
| 		if err != nil { | ||||
| 			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) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to get build config for %s. %s", repo.FullName, err) | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	netrc, err := remote_.Netrc(user, repo) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to generate netrc for %s. %s", repo.FullName, err) | ||||
| 		c.AbortWithError(500, err) | ||||
| 		_ = c.AbortWithError(500, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -479,7 +502,7 @@ func PostBuild(c *gin.Context) { | ||||
| 	err = persistBuildConfigs(configs, build.ID) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to persist build config for %s. %s", repo.FullName, err) | ||||
| 		c.AbortWithError(500, err) | ||||
| 		_ = c.AbortWithError(500, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -552,8 +575,12 @@ func PostBuild(c *gin.Context) { | ||||
| 	} | ||||
| 	c.JSON(202, build) | ||||
|  | ||||
| 	publishToTopic(c, build, repo, model.Enqueued) | ||||
| 	queueBuild(build, repo, buildItems) | ||||
| 	if err := publishToTopic(c, build, repo, model.Enqueued); err != nil { | ||||
| 		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) { | ||||
| @@ -565,13 +592,13 @@ func DeleteBuildLogs(c *gin.Context) { | ||||
|  | ||||
| 	build, err := store_.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	procs, err := store_.ProcList(build) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(404, err) | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"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/store" | ||||
| @@ -31,20 +32,20 @@ func FileList(c *gin.Context) { | ||||
| 	store_ := store.FromContext(c) | ||||
| 	num, err := strconv.ParseInt(c.Param("number"), 10, 64) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	repo := session.Repo(c) | ||||
| 	build, err := store_.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	files, err := store_.FileList(build) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -65,25 +66,25 @@ func FileGet(c *gin.Context) { | ||||
|  | ||||
| 	num, err := strconv.ParseInt(c.Param("number"), 10, 64) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	pid, err := strconv.Atoi(c.Param("proc")) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	build, err := store_.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	proc, err := store_.ProcFind(build, pid) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -110,5 +111,7 @@ func FileGet(c *gin.Context) { | ||||
| 		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) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to parse hook. %s", err) | ||||
| 		c.AbortWithError(400, err) | ||||
| 		_ = c.AbortWithError(400, err) | ||||
| 		return | ||||
| 	} | ||||
| 	if build == nil { | ||||
| @@ -107,12 +107,12 @@ func PostHook(c *gin.Context) { | ||||
| 	repo, err := store_.GetRepoName(tmpRepo.Owner + "/" + tmpRepo.Name) | ||||
| 	if err != nil { | ||||
| 		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 | ||||
| 	} | ||||
| 	if !repo.IsActive { | ||||
| 		log.Error().Msgf("ignoring hook. %s/%s is inactive.", tmpRepo.Owner, tmpRepo.Name) | ||||
| 		c.AbortWithError(204, err) | ||||
| 		_ = c.AbortWithError(204, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -122,7 +122,7 @@ func PostHook(c *gin.Context) { | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to parse token from hook for %s. %s", repo.FullName, err) | ||||
| 		c.AbortWithError(400, err) | ||||
| 		_ = c.AbortWithError(400, err) | ||||
| 		return | ||||
| 	} | ||||
| 	if parsed.Text != repo.FullName { | ||||
| @@ -139,7 +139,7 @@ func PostHook(c *gin.Context) { | ||||
|  | ||||
| 	if build.Event == model.EventPull && !repo.AllowPull { | ||||
| 		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) | ||||
| 		return | ||||
| 	} | ||||
| @@ -147,7 +147,7 @@ func PostHook(c *gin.Context) { | ||||
| 	user, err := store_.GetUser(repo.UserID) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to find repo owner %s. %s", repo.FullName, err) | ||||
| 		c.AbortWithError(500, err) | ||||
| 		_ = c.AbortWithError(500, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -171,14 +171,14 @@ func PostHook(c *gin.Context) { | ||||
| 	remoteYamlConfigs, err := configFetcher.Fetch(c) | ||||
| 	if err != nil { | ||||
| 		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 | ||||
| 	} | ||||
|  | ||||
| 	filtered, err := branchFiltered(build, remoteYamlConfigs) | ||||
| 	if err != nil { | ||||
| 		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 { | ||||
| 		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...) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to save commit for %s. %s", repo.FullName, err) | ||||
| 		c.AbortWithError(500, err) | ||||
| 		_ = c.AbortWithError(500, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -211,7 +211,7 @@ func PostHook(c *gin.Context) { | ||||
| 		_, err := findOrPersistPipelineConfig(repo, build, remoteYamlConfig) | ||||
| 		if err != nil { | ||||
| 			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 | ||||
| 		} | ||||
| 	} | ||||
| @@ -288,8 +288,12 @@ func PostHook(c *gin.Context) { | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	publishToTopic(c, build, repo, model.Enqueued) | ||||
| 	queueBuild(build, repo, buildItems) | ||||
| 	if err := publishToTopic(c, build, repo, model.Enqueued); err != nil { | ||||
| 		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 | ||||
| @@ -367,7 +371,7 @@ func findOrPersistPipelineConfig(repo *model.Repo, build *model.Build, remoteYam | ||||
| } | ||||
|  | ||||
| // 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{ | ||||
| 		Labels: map[string]string{ | ||||
| 			"repo":    repo.FullName, | ||||
| @@ -381,10 +385,10 @@ func publishToTopic(c *gin.Context, build *model.Build, repo *model.Repo, event | ||||
| 		Repo:  *repo, | ||||
| 		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 | ||||
| 	for _, item := range buildItems { | ||||
| 		if item.Proc.State == model.StatusSkipped { | ||||
| @@ -408,10 +412,12 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build | ||||
| 			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) | ||||
| 	} | ||||
| 	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) { | ||||
|   | ||||
| @@ -83,7 +83,7 @@ func HandleAuth(c *gin.Context) { | ||||
| 		// check the user's organization membership. | ||||
| 		if len(config.Orgs) != 0 { | ||||
| 			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) | ||||
| 				c.Redirect(303, "/login?error=access_denied") | ||||
| 				return | ||||
| @@ -120,7 +120,7 @@ func HandleAuth(c *gin.Context) { | ||||
| 	// check the user's organization membership. | ||||
| 	if len(config.Orgs) != 0 { | ||||
| 		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) | ||||
| 			c.Redirect(303, "/login?error=access_denied") | ||||
| 			return | ||||
| @@ -163,32 +163,32 @@ func GetLoginToken(c *gin.Context) { | ||||
| 	in := &tokenPayload{} | ||||
| 	err := c.Bind(in) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	login, err := remote.Auth(c, in.Access, in.Refresh) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusUnauthorized, err) | ||||
| 		_ = c.AbortWithError(http.StatusUnauthorized, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	user, err := store_.GetUserLogin(login) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusNotFound, err) | ||||
| 		_ = c.AbortWithError(http.StatusNotFound, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	exp := time.Now().Add(server.Config.Server.SessionExpires).Unix() | ||||
| 	token := token.New(token.SessToken, user.Login) | ||||
| 	tokenstr, err := token.SignExpires(user.Hash, exp) | ||||
| 	newToken := token.New(token.SessToken, user.Login) | ||||
| 	tokenStr, err := newToken.SignExpires(user.Hash, exp) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.JSON(http.StatusOK, &tokenPayload{ | ||||
| 		Access:  tokenstr, | ||||
| 		Access:  tokenStr, | ||||
| 		Expires: exp - time.Now().Unix(), | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -22,6 +22,7 @@ import ( | ||||
|  | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"github.com/gorilla/securecookie" | ||||
| 	"github.com/rs/zerolog/log" | ||||
|  | ||||
| 	"github.com/woodpecker-ci/woodpecker/server" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| @@ -104,7 +105,7 @@ func PatchRepo(c *gin.Context) { | ||||
|  | ||||
| 	in := new(model.RepoPatch) | ||||
| 	if err := c.Bind(in); err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -143,7 +144,7 @@ func PatchRepo(c *gin.Context) { | ||||
|  | ||||
| 	err := store_.UpdateRepo(repo) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -158,7 +159,7 @@ func ChownRepo(c *gin.Context) { | ||||
|  | ||||
| 	err := store_.UpdateRepo(repo) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
| 	c.JSON(http.StatusOK, repo) | ||||
| @@ -180,7 +181,7 @@ func GetRepoBranches(c *gin.Context) { | ||||
|  | ||||
| 	branches, err := r.Branches(c, user, repo) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -200,20 +201,20 @@ func DeleteRepo(c *gin.Context) { | ||||
|  | ||||
| 	err := store_.UpdateRepo(repo) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if remove { | ||||
| 		err := store_.DeleteRepo(repo) | ||||
| 		if err != nil { | ||||
| 			c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 			_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := remote_.Deactivate(c, user, repo, server.Config.Server.Host); err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
| 	c.JSON(200, repo) | ||||
| @@ -241,26 +242,33 @@ func RepairRepo(c *gin.Context) { | ||||
| 		sig, | ||||
| 	) | ||||
|  | ||||
| 	_ = remote_.Deactivate(c, user, repo, host) | ||||
| 	err = remote_.Activate(c, user, repo, link) | ||||
| 	if err != nil { | ||||
| 	if err := remote_.Deactivate(c, user, repo, host); err != nil { | ||||
| 		log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName) | ||||
| 	} | ||||
| 	if err := remote_.Activate(c, user, repo, link); err != nil { | ||||
| 		c.String(500, err.Error()) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	from, err := remote_.Repo(c, user, repo.Owner, repo.Name) | ||||
| 	if err == nil { | ||||
| 		repo.Name = from.Name | ||||
| 		repo.Owner = from.Owner | ||||
| 		repo.FullName = from.FullName | ||||
| 		repo.Avatar = from.Avatar | ||||
| 		repo.Link = from.Link | ||||
| 		repo.Clone = from.Clone | ||||
| 		repo.IsSCMPrivate = from.IsSCMPrivate | ||||
| 		if repo.IsSCMPrivate != from.IsSCMPrivate { | ||||
| 			repo.ResetVisibility() | ||||
| 		} | ||||
| 		store_.UpdateRepo(repo) | ||||
| 	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.Owner = from.Owner | ||||
| 	repo.FullName = from.FullName | ||||
| 	repo.Avatar = from.Avatar | ||||
| 	repo.Link = from.Link | ||||
| 	repo.Clone = from.Clone | ||||
| 	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) | ||||
| @@ -275,19 +283,19 @@ func MoveRepo(c *gin.Context) { | ||||
| 	to, exists := c.GetQuery("to") | ||||
| 	if !exists { | ||||
| 		err := fmt.Errorf("Missing required to query value") | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	owner, name, errParse := model.ParseRepo(to) | ||||
| 	if errParse != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, errParse) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, errParse) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	from, err := remote_.Repo(c, user, owner, name) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
| 	if !from.Perm.Admin { | ||||
| @@ -308,7 +316,7 @@ func MoveRepo(c *gin.Context) { | ||||
|  | ||||
| 	errStore := store_.UpdateRepo(repo) | ||||
| 	if errStore != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, errStore) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, errStore) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -328,10 +336,10 @@ func MoveRepo(c *gin.Context) { | ||||
| 		sig, | ||||
| 	) | ||||
|  | ||||
| 	// TODO: check if we should handle that error | ||||
| 	remote_.Deactivate(c, user, repo, host) | ||||
| 	err = remote_.Activate(c, user, repo, link) | ||||
| 	if err != nil { | ||||
| 	if err := remote_.Deactivate(c, user, repo, host); err != nil { | ||||
| 		log.Trace().Err(err).Msgf("deactivate repo '%s' for move to activate later, got an error", repo.FullName) | ||||
| 	} | ||||
| 	if err := remote_.Activate(c, user, repo, link); err != nil { | ||||
| 		c.String(500, err.Error()) | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -52,7 +52,7 @@ func EventStreamSSE(c *gin.Context) { | ||||
| 	} | ||||
|  | ||||
| 	// ping the client | ||||
| 	io.WriteString(rw, ": ping\n\n") | ||||
| 	logWriteStringErr(io.WriteString(rw, ": ping\n\n")) | ||||
| 	flusher.Flush() | ||||
|  | ||||
| 	log.Debug().Msg("user feed: connection opened") | ||||
| @@ -78,9 +78,10 @@ func EventStreamSSE(c *gin.Context) { | ||||
| 	}() | ||||
|  | ||||
| 	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() { | ||||
| 				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"] | ||||
| 			priv := m.Labels["private"] | ||||
| @@ -93,6 +94,9 @@ func EventStreamSSE(c *gin.Context) { | ||||
| 				} | ||||
| 			} | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			log.Error().Err(err).Msg("Subscribe failed") | ||||
| 		} | ||||
| 		cancel() | ||||
| 	}() | ||||
|  | ||||
| @@ -103,13 +107,13 @@ func EventStreamSSE(c *gin.Context) { | ||||
| 		case <-ctx.Done(): | ||||
| 			return | ||||
| 		case <-time.After(time.Second * 30): | ||||
| 			io.WriteString(rw, ": ping\n\n") | ||||
| 			logWriteStringErr(io.WriteString(rw, ": ping\n\n")) | ||||
| 			flusher.Flush() | ||||
| 		case buf, ok := <-eventc: | ||||
| 			if ok { | ||||
| 				io.WriteString(rw, "data: ") | ||||
| 				rw.Write(buf) | ||||
| 				io.WriteString(rw, "\n\n") | ||||
| 				logWriteStringErr(io.WriteString(rw, "data: ")) | ||||
| 				logWriteStringErr(rw.Write(buf)) | ||||
| 				logWriteStringErr(io.WriteString(rw, "\n\n")) | ||||
| 				flusher.Flush() | ||||
| 			} | ||||
| 		} | ||||
| @@ -130,7 +134,7 @@ func LogStreamSSE(c *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	io.WriteString(rw, ": ping\n\n") | ||||
| 	logWriteStringErr(io.WriteString(rw, ": ping\n\n")) | ||||
| 	flusher.Flush() | ||||
|  | ||||
| 	repo := session.Repo(c) | ||||
| @@ -144,18 +148,18 @@ func LogStreamSSE(c *gin.Context) { | ||||
| 	build, err := store_.GetBuildNumber(repo, buildn) | ||||
| 	if err != nil { | ||||
| 		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 | ||||
| 	} | ||||
| 	proc, err := store_.ProcFind(build, jobn) | ||||
| 	if err != nil { | ||||
| 		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 | ||||
| 	} | ||||
| 	if proc.State != model.StatusRunning { | ||||
| 		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 | ||||
| 	} | ||||
|  | ||||
| @@ -174,9 +178,10 @@ func LogStreamSSE(c *gin.Context) { | ||||
|  | ||||
| 	go func() { | ||||
| 		// 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() { | ||||
| 				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 { | ||||
| 				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() | ||||
| 	}() | ||||
| @@ -215,16 +223,16 @@ func LogStreamSSE(c *gin.Context) { | ||||
| 		case <-ctx.Done(): | ||||
| 			return | ||||
| 		case <-time.After(time.Second * 30): | ||||
| 			io.WriteString(rw, ": ping\n\n") | ||||
| 			logWriteStringErr(io.WriteString(rw, ": ping\n\n")) | ||||
| 			flusher.Flush() | ||||
| 		case buf, ok := <-logc: | ||||
| 			if ok { | ||||
| 				if id > last { | ||||
| 					io.WriteString(rw, "id: "+strconv.Itoa(id)) | ||||
| 					io.WriteString(rw, "\n") | ||||
| 					io.WriteString(rw, "data: ") | ||||
| 					rw.Write(buf) | ||||
| 					io.WriteString(rw, "\n\n") | ||||
| 					logWriteStringErr(io.WriteString(rw, "id: "+strconv.Itoa(id))) | ||||
| 					logWriteStringErr(io.WriteString(rw, "\n")) | ||||
| 					logWriteStringErr(io.WriteString(rw, "data: ")) | ||||
| 					logWriteStringErr(rw.Write(buf)) | ||||
| 					logWriteStringErr(io.WriteString(rw, "\n\n")) | ||||
| 					flusher.Flush() | ||||
| 				} | ||||
| 				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) | ||||
|  | ||||
| 		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) | ||||
|  | ||||
| @@ -138,7 +141,7 @@ func PostToken(c *gin.Context) { | ||||
| 	user := session.User(c) | ||||
| 	tokenString, err := token.New(token.UserToken, user.Login).Sign(user.Hash) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
| 	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) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
| 	c.String(http.StatusOK, tokenString) | ||||
|   | ||||
| @@ -55,13 +55,13 @@ func SetLogLevel(c *gin.Context) { | ||||
| 		LogLevel string `json:"log-level"` | ||||
| 	}{} | ||||
| 	if err := c.Bind(&logLevel); err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	lvl, err := zerolog.ParseLevel(logLevel.LogLevel) | ||||
| 	if err != nil { | ||||
| 		c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -81,7 +81,9 @@ func (s *RPC) Next(c context.Context, filter rpc.Filter) (*rpc.Pipeline, error) | ||||
| 			err = json.Unmarshal(task.Data, pipeline) | ||||
| 			return pipeline, err | ||||
| 		} 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, | ||||
| 		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 | ||||
| } | ||||
| @@ -279,7 +283,9 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error { | ||||
| 			Repo:  *repo, | ||||
| 			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) | ||||
| @@ -373,7 +379,9 @@ func isMultiPipeline(procs []*model.Proc) bool { | ||||
| func (s *RPC) Log(c context.Context, id string, line *rpc.Line) error { | ||||
| 	entry := new(logging.Entry) | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| @@ -416,9 +424,14 @@ func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *m | ||||
| 	user, err := s.store.GetUser(repo.UserID) | ||||
| 	if err == nil { | ||||
| 		if refresher, ok := s.remote.(remote.Refresher); ok { | ||||
| 			ok, _ := refresher.Refresh(ctx, user) | ||||
| 			if ok { | ||||
| 				s.store.UpdateUser(user) | ||||
| 			ok, err := refresher.Refresh(ctx, user) | ||||
| 			if err != nil { | ||||
| 				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) | ||||
| @@ -441,7 +454,9 @@ func (s *RPC) notify(c context.Context, repo *model.Repo, build *model.Build, pr | ||||
| 		Repo:  *repo, | ||||
| 		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) { | ||||
|   | ||||
| @@ -132,11 +132,15 @@ func (l *log) Snapshot(c context.Context, path string, w io.Writer) error { | ||||
| 		return ErrNotFound | ||||
| 	} | ||||
| 	s.Lock() | ||||
| 	defer s.Unlock() | ||||
| 	for _, entry := range s.list { | ||||
| 		w.Write(entry.Data) | ||||
| 		w.Write(cr) | ||||
| 		if _, err := w.Write(entry.Data); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err := w.Write(cr); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	s.Unlock() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,8 @@ import ( | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestLogging(t *testing.T) { | ||||
| @@ -22,27 +24,27 @@ func TestLogging(t *testing.T) { | ||||
| 	) | ||||
|  | ||||
| 	logger := New() | ||||
| 	logger.Open(ctx, testPath) | ||||
| 	assert.NoError(t, logger.Open(ctx, testPath)) | ||||
| 	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() { | ||||
| 		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) | ||||
|  | ||||
| 	wg.Add(4) | ||||
| 	go func() { | ||||
| 		logger.Write(ctx, testPath, testEntry) | ||||
| 		logger.Write(ctx, testPath, testEntry) | ||||
| 		assert.NoError(t, logger.Write(ctx, testPath, testEntry)) | ||||
| 		assert.NoError(t, logger.Write(ctx, testPath, testEntry)) | ||||
| 	}() | ||||
|  | ||||
| 	wg.Wait() | ||||
|  | ||||
| 	wg.Add(1) | ||||
| 	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) | ||||
|   | ||||
| @@ -5,6 +5,8 @@ import ( | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestPubsub(t *testing.T) { | ||||
| @@ -22,12 +24,12 @@ func TestPubsub(t *testing.T) { | ||||
| 	) | ||||
|  | ||||
| 	broker := New() | ||||
| 	broker.Create(ctx, testTopic) | ||||
| 	assert.NoError(t, broker.Create(ctx, testTopic)) | ||||
| 	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() { | ||||
| 		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) | ||||
| @@ -38,7 +40,7 @@ func TestPubsub(t *testing.T) { | ||||
|  | ||||
| 	wg.Add(2) | ||||
| 	go func() { | ||||
| 		broker.Publish(ctx, testTopic, testMessage) | ||||
| 		assert.NoError(t, broker.Publish(ctx, testTopic, testMessage)) | ||||
| 	}() | ||||
|  | ||||
| 	wg.Wait() | ||||
| @@ -80,9 +82,9 @@ func TestSubscriptionClosed(t *testing.T) { | ||||
| 	) | ||||
|  | ||||
| 	broker := New() | ||||
| 	broker.Create(context.Background(), testTopic) | ||||
| 	assert.NoError(t, broker.Create(context.Background(), testTopic)) | ||||
| 	go func() { | ||||
| 		broker.Subscribe(context.Background(), testTopic, testCallback) | ||||
| 		assert.NoError(t, broker.Subscribe(context.Background(), testTopic, testCallback)) | ||||
| 		wg.Done() | ||||
| 	}() | ||||
|  | ||||
| @@ -93,7 +95,7 @@ func TestSubscriptionClosed(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	wg.Add(1) | ||||
| 	broker.Remove(context.Background(), testTopic) | ||||
| 	assert.NoError(t, broker.Remove(context.Background(), testTopic)) | ||||
| 	wg.Wait() | ||||
|  | ||||
| 	if _, ok := broker.(*publisher).topics[testTopic]; ok { | ||||
|   | ||||
| @@ -6,6 +6,8 @@ import ( | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| var noContext = context.Background() | ||||
| @@ -14,7 +16,7 @@ func TestFifo(t *testing.T) { | ||||
| 	want := &Task{ID: "1"} | ||||
|  | ||||
| 	q := New() | ||||
| 	q.Push(noContext, want) | ||||
| 	assert.NoError(t, q.Push(noContext, want)) | ||||
| 	info := q.Info(noContext) | ||||
| 	if len(info.Pending) != 1 { | ||||
| 		t.Errorf("expect task in pending queue") | ||||
| @@ -37,7 +39,7 @@ func TestFifo(t *testing.T) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	q.Done(noContext, got.ID, StatusSuccess) | ||||
| 	assert.NoError(t, q.Done(noContext, got.ID, StatusSuccess)) | ||||
| 	info = q.Info(noContext) | ||||
| 	if len(info.Pending) != 0 { | ||||
| 		t.Errorf("expect task removed from pending queue") | ||||
| @@ -54,7 +56,7 @@ func TestFifoExpire(t *testing.T) { | ||||
|  | ||||
| 	q := New().(*fifo) | ||||
| 	q.extension = 0 | ||||
| 	q.Push(noContext, want) | ||||
| 	assert.NoError(t, q.Push(noContext, want)) | ||||
| 	info := q.Info(noContext) | ||||
| 	if len(info.Pending) != 1 { | ||||
| 		t.Errorf("expect task in pending queue") | ||||
| @@ -78,7 +80,7 @@ func TestFifoWait(t *testing.T) { | ||||
| 	want := &Task{ID: "1"} | ||||
|  | ||||
| 	q := New().(*fifo) | ||||
| 	q.Push(noContext, want) | ||||
| 	assert.NoError(t, q.Push(noContext, want)) | ||||
|  | ||||
| 	got, _ := q.Poll(noContext, func(*Task) bool { return true }) | ||||
| 	if got != want { | ||||
| @@ -89,12 +91,12 @@ func TestFifoWait(t *testing.T) { | ||||
| 	var wg sync.WaitGroup | ||||
| 	wg.Add(1) | ||||
| 	go func() { | ||||
| 		q.Wait(noContext, got.ID) | ||||
| 		assert.NoError(t, q.Wait(noContext, got.ID)) | ||||
| 		wg.Done() | ||||
| 	}() | ||||
|  | ||||
| 	<-time.After(time.Millisecond) | ||||
| 	q.Done(noContext, got.ID, StatusSuccess) | ||||
| 	assert.NoError(t, q.Done(noContext, got.ID, StatusSuccess)) | ||||
| 	wg.Wait() | ||||
| } | ||||
|  | ||||
| @@ -102,7 +104,7 @@ func TestFifoEvict(t *testing.T) { | ||||
| 	t1 := &Task{ID: "1"} | ||||
|  | ||||
| 	q := New() | ||||
| 	q.Push(noContext, t1) | ||||
| 	assert.NoError(t, q.Push(noContext, t1)) | ||||
| 	info := q.Info(noContext) | ||||
| 	if len(info.Pending) != 1 { | ||||
| 		t.Errorf("expect task in pending queue") | ||||
| @@ -131,7 +133,7 @@ func TestFifoDependencies(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	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 }) | ||||
| 	if got != task1 { | ||||
| @@ -139,7 +141,7 @@ func TestFifoDependencies(t *testing.T) { | ||||
| 		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 }) | ||||
| 	if got != task2 { | ||||
| @@ -167,7 +169,7 @@ func TestFifoErrors(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	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 }) | ||||
| 	if got != task1 { | ||||
| @@ -175,7 +177,7 @@ func TestFifoErrors(t *testing.T) { | ||||
| 		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 }) | ||||
| 	if got != task2 { | ||||
| @@ -216,7 +218,7 @@ func TestFifoErrors2(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	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++ { | ||||
| 		got, _ := q.Poll(noContext, func(*Task) bool { return true }) | ||||
| @@ -226,10 +228,10 @@ func TestFifoErrors2(t *testing.T) { | ||||
| 		} | ||||
|  | ||||
| 		if got != task1 { | ||||
| 			q.Done(noContext, got.ID, StatusSuccess) | ||||
| 			assert.NoError(t, q.Done(noContext, got.ID, StatusSuccess)) | ||||
| 		} | ||||
| 		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.PushAtOnce(noContext, []*Task{task2, task3, task1}) | ||||
| 	assert.NoError(t, q.PushAtOnce(noContext, []*Task{task2, task3, task1})) | ||||
|  | ||||
| 	obtainedWorkCh := make(chan *Task) | ||||
|  | ||||
| @@ -291,7 +293,7 @@ func TestFifoErrorsMultiThread(t *testing.T) { | ||||
| 					return | ||||
| 				} else { | ||||
| 					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() { | ||||
| 						for { | ||||
| 							fmt.Printf("Worker spawned\n") | ||||
| @@ -306,7 +308,7 @@ func TestFifoErrorsMultiThread(t *testing.T) { | ||||
| 					return | ||||
| 				} else { | ||||
| 					task2Processed = true | ||||
| 					q.Done(noContext, got.ID, StatusSuccess) | ||||
| 					assert.NoError(t, q.Done(noContext, got.ID, StatusSuccess)) | ||||
| 					go func() { | ||||
| 						for { | ||||
| 							fmt.Printf("Worker spawned\n") | ||||
| @@ -356,14 +358,14 @@ func TestFifoTransitiveErrors(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	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 }) | ||||
| 	if got != task1 { | ||||
| 		t.Errorf("expect task1 returned from queue as task2 depends on it") | ||||
| 		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 }) | ||||
| 	if got != task2 { | ||||
| @@ -374,7 +376,7 @@ func TestFifoTransitiveErrors(t *testing.T) { | ||||
| 		t.Errorf("expect task2 should not run, since task1 failed") | ||||
| 		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 }) | ||||
| 	if got != task3 { | ||||
| @@ -406,12 +408,12 @@ func TestFifoCancel(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	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.Error(noContext, task1.ID, fmt.Errorf("cancelled")) | ||||
| 	q.Error(noContext, task2.ID, fmt.Errorf("cancelled")) | ||||
| 	q.Error(noContext, task3.ID, fmt.Errorf("cancelled")) | ||||
| 	assert.NoError(t, q.Error(noContext, task1.ID, fmt.Errorf("cancelled"))) | ||||
| 	assert.NoError(t, q.Error(noContext, task2.ID, fmt.Errorf("cancelled"))) | ||||
| 	assert.NoError(t, q.Error(noContext, task3.ID, fmt.Errorf("cancelled"))) | ||||
|  | ||||
| 	info := q.Info(noContext) | ||||
| 	if len(info.Pending) != 0 { | ||||
| @@ -435,7 +437,7 @@ func TestFifoPause(t *testing.T) { | ||||
|  | ||||
| 	q.Pause() | ||||
| 	t0 := time.Now() | ||||
| 	q.Push(noContext, task1) | ||||
| 	assert.NoError(t, q.Push(noContext, task1)) | ||||
| 	time.Sleep(20 * time.Millisecond) | ||||
| 	q.Resume() | ||||
|  | ||||
| @@ -447,7 +449,7 @@ func TestFifoPause(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	q.Pause() | ||||
| 	q.Push(noContext, task1) | ||||
| 	assert.NoError(t, q.Push(noContext, task1)) | ||||
| 	q.Resume() | ||||
| 	_, _ = q.Poll(noContext, func(*Task) bool { return true }) | ||||
| } | ||||
| @@ -459,7 +461,7 @@ func TestFifoPauseResume(t *testing.T) { | ||||
|  | ||||
| 	q := New().(*fifo) | ||||
| 	q.Pause() | ||||
| 	q.Push(noContext, task1) | ||||
| 	assert.NoError(t, q.Push(noContext, task1)) | ||||
| 	q.Resume() | ||||
|  | ||||
| 	_, _ = q.Poll(noContext, func(*Task) bool { return true }) | ||||
| @@ -484,7 +486,7 @@ func TestWaitingVsPending(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	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 }) | ||||
|  | ||||
| @@ -493,7 +495,7 @@ func TestWaitingVsPending(t *testing.T) { | ||||
| 		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 }) | ||||
|  | ||||
| 	info = q.Info(noContext) | ||||
|   | ||||
| @@ -18,6 +18,7 @@ package queue | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/rs/zerolog/log" | ||||
|  | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| @@ -38,7 +39,9 @@ func WithTaskStore(q Queue, s model.TaskStore) Queue { | ||||
| 			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} | ||||
| } | ||||
|  | ||||
| @@ -49,35 +52,44 @@ type persistentQueue struct { | ||||
|  | ||||
| // Push pushes a task to the tail of this queue. | ||||
| 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, | ||||
| 		Data:         task.Data, | ||||
| 		Labels:       task.Labels, | ||||
| 		Dependencies: task.Dependencies, | ||||
| 		RunOn:        task.RunOn, | ||||
| 	}) | ||||
| 	}); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err := q.Queue.Push(c, task) | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| // PushAtOnce pushes multiple tasks to the tail of this queue. | ||||
| 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 { | ||||
| 		q.store.TaskInsert(&model.Task{ | ||||
| 		if err := q.store.TaskInsert(&model.Task{ | ||||
| 			ID:           task.ID, | ||||
| 			Data:         task.Data, | ||||
| 			Labels:       task.Labels, | ||||
| 			Dependencies: task.Dependencies, | ||||
| 			RunOn:        task.RunOn, | ||||
| 		}) | ||||
| 		}); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	err := q.Queue.PushAtOnce(c, tasks) | ||||
| 	if err != nil { | ||||
| 		for _, task := range tasks { | ||||
| 			q.store.TaskDelete(task.ID) | ||||
| 			if err := q.store.TaskDelete(task.ID); err != nil { | ||||
| 				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 { | ||||
| 	err := q.Queue.Evict(c, id) | ||||
| 	if err == nil { | ||||
| 		q.store.TaskDelete(id) | ||||
| 		return q.store.TaskDelete(id) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // EvictAtOnce removes a pending task from the queue. | ||||
| func (q *persistentQueue) EvictAtOnce(c context.Context, ids []string) error { | ||||
| 	err := q.Queue.EvictAtOnce(c, ids) | ||||
| 	if err == nil { | ||||
| 		for _, id := range ids { | ||||
| 			q.store.TaskDelete(id) | ||||
| 	if err := q.Queue.EvictAtOnce(c, ids); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, id := range ids { | ||||
| 		if err := q.store.TaskDelete(id); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	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 { | ||||
| 		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{ | ||||
| 		Active: true, | ||||
|   | ||||
| @@ -30,7 +30,6 @@ import ( | ||||
|  | ||||
| const ( | ||||
| 	get  = "GET" | ||||
| 	put  = "PUT" | ||||
| 	post = "POST" | ||||
| 	del  = "DELETE" | ||||
| ) | ||||
| @@ -213,7 +212,7 @@ func (c *Client) do(rawurl, method string, in, out interface{}) (*string, error) | ||||
| 	// error response. | ||||
| 	if resp.StatusCode > http.StatusPartialContent { | ||||
| 		err := Error{} | ||||
| 		json.NewDecoder(resp.Body).Decode(&err) | ||||
| 		_ = json.NewDecoder(resp.Body).Decode(&err) | ||||
| 		err.Status = resp.StatusCode | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
| @@ -28,13 +28,7 @@ const ( | ||||
| 	hookPush        = "repo:push" | ||||
| 	hookPullCreated = "pullrequest:created" | ||||
| 	hookPullUpdated = "pullrequest:updated" | ||||
|  | ||||
| 	changeBranch      = "branch" | ||||
| 	changeNamedBranch = "named_branch" | ||||
|  | ||||
| 	stateMerged   = "MERGED" | ||||
| 	stateDeclined = "DECLINED" | ||||
| 	stateOpen     = "OPEN" | ||||
| 	stateOpen       = "OPEN" | ||||
| ) | ||||
|  | ||||
| // parseHook parses a Bitbucket hook from an http.Request request and returns | ||||
|   | ||||
| @@ -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) { | ||||
| 	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")) { | ||||
| @@ -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 = ` | ||||
| { | ||||
|     "code":0, | ||||
|   | ||||
| @@ -76,7 +76,7 @@ func createRepoHook(c *gin.Context) { | ||||
| 			URL  string `json:"url"` | ||||
| 		} `json:"config"` | ||||
| 	}{} | ||||
| 	c.BindJSON(&in) | ||||
| 	_ = c.BindJSON(&in) | ||||
| 	if in.Type != "gitea" || | ||||
| 		in.Conf.Type != "json" || | ||||
| 		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 | ||||
| // list to the common Woodpecker repository structure. | ||||
| 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++ { | ||||
| 		select { | ||||
| 		case err, _ := <-errc: | ||||
| 		case err := <-errc: | ||||
| 			errors = append(errors, err) | ||||
| 		case fileMeta, _ := <-fc: | ||||
| 		case fileMeta := <-fc: | ||||
| 			files = append(files, fileMeta) | ||||
| 		} | ||||
| 	} | ||||
| @@ -464,7 +464,7 @@ func repoStatus(c context.Context, client *github.Client, r *model.Repo, b *mode | ||||
| 	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 { | ||||
| 	matches := reDeploy.FindStringSubmatch(b.Link) | ||||
|   | ||||
| @@ -150,11 +150,6 @@ var ( | ||||
| 		Token: "cfcd2084", | ||||
| 	} | ||||
|  | ||||
| 	fakeUserNoRepos = &model.User{ | ||||
| 		Login: "octocat", | ||||
| 		Token: "repos_not_found", | ||||
| 	} | ||||
|  | ||||
| 	fakeRepo = &model.Repo{ | ||||
| 		Owner:        "octocat", | ||||
| 		Name:         "Hello-World", | ||||
| @@ -170,8 +165,4 @@ var ( | ||||
| 		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"` | ||||
| 		} `json:"config"` | ||||
| 	}{} | ||||
| 	c.BindJSON(&in) | ||||
| 	_ = c.BindJSON(&in) | ||||
| 	if in.Type != "gogs" || | ||||
| 		in.Conf.Type != "json" || | ||||
| 		in.Conf.URL != "http://localhost" { | ||||
|   | ||||
| @@ -104,7 +104,10 @@ func SetPerm() gin.HandlerFunc { | ||||
| 					perm.Repo = repo.FullName | ||||
| 					perm.UserID = user.ID | ||||
| 					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: | ||||
| 			c.String(401, "User not authorized") | ||||
| 			c.Abort() | ||||
| 		case user.Admin == false: | ||||
| 		case !user.Admin: | ||||
| 			c.String(403, "User not authorized") | ||||
| 			c.Abort() | ||||
| 		default: | ||||
| @@ -95,7 +95,7 @@ func MustRepoAdmin() gin.HandlerFunc { | ||||
| 		case user == nil: | ||||
| 			c.String(401, "User not authorized") | ||||
| 			c.Abort() | ||||
| 		case perm.Admin == false: | ||||
| 		case !perm.Admin: | ||||
| 			c.String(403, "User not authorized") | ||||
| 			c.Abort() | ||||
| 		default: | ||||
|   | ||||
| @@ -53,8 +53,10 @@ func Refresh(c *gin.Context) { | ||||
| 	// attempts to refresh the access token. If the | ||||
| 	// token is refreshed, we must also persist to the | ||||
| 	// database. | ||||
| 	ok, _ = refresher.Refresh(c, user) | ||||
| 	if ok { | ||||
| 	ok, err := refresher.Refresh(c, user) | ||||
| 	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) | ||||
| 		if err != nil { | ||||
| 			// we only log the error at this time. not sure | ||||
|   | ||||
| @@ -40,9 +40,8 @@ type Syncer struct { | ||||
| // synchronized with the local datastore. | ||||
| type FilterFunc func(*model.Repo) bool | ||||
|  | ||||
| // NamespaceFilter | ||||
| func NamespaceFilter(namespaces map[string]bool) FilterFunc { | ||||
| 	if namespaces == nil || len(namespaces) == 0 { | ||||
| 	if len(namespaces) == 0 { | ||||
| 		return noopFilter | ||||
| 	} | ||||
| 	return func(repo *model.Repo) bool { | ||||
|   | ||||
| @@ -16,12 +16,13 @@ package web | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"text/template" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"github.com/rs/zerolog/log" | ||||
|  | ||||
| 	"github.com/woodpecker-ci/woodpecker/server" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/router/middleware/session" | ||||
| 	"github.com/woodpecker-ci/woodpecker/shared/token" | ||||
| @@ -29,8 +30,6 @@ import ( | ||||
| ) | ||||
|  | ||||
| func WebConfig(c *gin.Context) { | ||||
| 	var err error | ||||
|  | ||||
| 	user := session.User(c) | ||||
|  | ||||
| 	var csrf string | ||||
| @@ -65,10 +64,9 @@ func WebConfig(c *gin.Context) { | ||||
| 	c.Header("Content-Type", "text/javascript; charset=utf-8") | ||||
| 	tmpl := template.Must(template.New("").Funcs(funcMap).Parse(configTemplate)) | ||||
|  | ||||
| 	err = tmpl.Execute(c.Writer, configData) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 		c.AbortWithError(http.StatusInternalServerError, nil) | ||||
| 	if err := tmpl.Execute(c.Writer, configData); err != nil { | ||||
| 		log.Error().Err(err).Msgf("could not execute template") | ||||
| 		c.AbortWithStatus(http.StatusInternalServerError) | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -23,6 +23,7 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"github.com/rs/zerolog/log" | ||||
|  | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| 	"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) { | ||||
| 	rw.WriteHeader(200) | ||||
|  | ||||
| 	var csrf string | ||||
| 	var user, _ = ToUser(r.Context()) | ||||
| 	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") | ||||
|  | ||||
| 	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 { | ||||
|   | ||||
							
								
								
									
										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 | ||||
| # github.com/pkg/errors v0.9.1 | ||||
| ## explicit | ||||
| github.com/pkg/errors | ||||
| # github.com/pmezard/go-difflib v1.0.0 | ||||
| github.com/pmezard/go-difflib/difflib | ||||
|   | ||||
		Reference in New Issue
	
	Block a user