From d2b09d854f10ca60994fba27444c26529706e655 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Tue, 22 Feb 2022 15:01:29 +0100 Subject: [PATCH] *: use new errors handling library Implement a new error handling library based on pkg/errors. It provides stack saving on wrapping and exports some function to add stack saving also to external errors. It also implements custom zerolog error formatting without adding too much verbosity by just printing the chain error file:line without a full stack trace of every error. * Add a --detailed-errors options to print error with they full chain * Wrap all error returns. Use errors.WithStack to wrap without adding a new messsage and error.Wrap[f] to add a message. * Add golangci-lint wrapcheck to check that external packages errors are wrapped. This won't check that internal packages error are wrapped. But we want also to ensure this case so we'll have to find something else to check also these. --- .golangci.yml | 25 +- cmd/agola/cmd/agola.go | 16 +- cmd/agola/cmd/completion.go | 5 +- cmd/agola/cmd/directrunstart.go | 32 +- cmd/agola/cmd/logdelete.go | 4 +- cmd/agola/cmd/logget.go | 6 +- cmd/agola/cmd/orgcreate.go | 4 +- cmd/agola/cmd/orgdelete.go | 4 +- cmd/agola/cmd/orgmemberadd.go | 4 +- cmd/agola/cmd/orgmemberlist.go | 6 +- cmd/agola/cmd/orgmemberremove.go | 4 +- cmd/agola/cmd/projectcreate.go | 4 +- cmd/agola/cmd/projectdelete.go | 4 +- cmd/agola/cmd/projectgroupcreate.go | 4 +- cmd/agola/cmd/projectgroupdelete.go | 4 +- cmd/agola/cmd/projectgroupupdate.go | 4 +- cmd/agola/cmd/projectlist.go | 3 +- cmd/agola/cmd/projectreconfig.go | 4 +- cmd/agola/cmd/projectsecretcreate.go | 10 +- cmd/agola/cmd/projectsecretdelete.go | 6 +- cmd/agola/cmd/projectsecretlist.go | 10 +- cmd/agola/cmd/projectsecretupdate.go | 10 +- cmd/agola/cmd/projectupdate.go | 4 +- cmd/agola/cmd/projectvariablecreate.go | 10 +- cmd/agola/cmd/projectvariabledelete.go | 6 +- cmd/agola/cmd/projectvariablelist.go | 10 +- cmd/agola/cmd/projectvariableupdate.go | 10 +- cmd/agola/cmd/remotesourcecreate.go | 4 +- cmd/agola/cmd/remotesourcelist.go | 3 +- cmd/agola/cmd/remotesourceupdate.go | 4 +- cmd/agola/cmd/runcreate.go | 6 +- cmd/agola/cmd/runlist.go | 6 +- cmd/agola/cmd/serve.go | 22 +- cmd/agola/cmd/usercreate.go | 4 +- cmd/agola/cmd/userdelete.go | 4 +- cmd/agola/cmd/userlacreate.go | 4 +- cmd/agola/cmd/userladelete.go | 4 +- cmd/agola/cmd/userlist.go | 3 +- cmd/agola/cmd/usertokencreate.go | 4 +- cmd/agola/cmd/usertokendelete.go | 4 +- cmd/agola/cmd/version.go | 3 +- cmd/toolbox/cmd/createfile.go | 7 +- cmd/toolbox/cmd/template.go | 19 +- doc/devel.md | 10 +- go.mod | 1 - internal/common/common.go | 14 +- internal/config/config.go | 74 ++--- internal/config/config_test.go | 15 +- internal/config/jsonnet.go | 6 +- internal/config/starlark.go | 38 +-- internal/config/starlark_test.go | 4 +- internal/datamanager/changes.go | 20 +- internal/datamanager/data.go | 72 ++-- internal/datamanager/datamanager.go | 4 +- internal/datamanager/datamanager_test.go | 36 +- internal/datamanager/wal.go | 135 ++++---- internal/db/create.go | 18 +- internal/db/db.go | 36 +- internal/errors/errors.go | 89 +++++ internal/errors/format.go | 47 +++ internal/errors/go113.go | 38 +++ internal/errors/stack.go | 181 ++++++++++ internal/errors/zerolog.go | 63 ++++ internal/etcd/etcd.go | 24 +- internal/etcd/mutex.go | 1 + internal/git-handler/handler.go | 10 +- internal/git-save/save.go | 60 ++-- internal/gitsources/agolagit/agolagit.go | 19 +- internal/gitsources/gitea/gitea.go | 70 ++-- internal/gitsources/gitea/parse.go | 11 +- internal/gitsources/github/github.go | 71 ++-- internal/gitsources/github/parse.go | 8 +- internal/gitsources/gitlab/gitlab.go | 54 +-- internal/gitsources/gitlab/parse.go | 11 +- internal/gitsources/gitsource.go | 3 +- internal/objectstorage/atomic.go | 8 +- internal/objectstorage/objectstorage.go | 6 +- internal/objectstorage/posix.go | 30 +- internal/objectstorage/posixflat.go | 34 +- internal/objectstorage/posixflat_test.go | 2 +- internal/objectstorage/s3.go | 31 +- internal/runconfig/runconfig.go | 7 +- internal/runconfig/runconfig_test.go | 8 +- internal/sequence/sequence.go | 18 +- internal/sequence/sequence_test.go | 3 +- internal/services/common/gitsource.go | 25 +- internal/services/common/jwt.go | 7 +- internal/services/common/run.go | 5 +- internal/services/config/config.go | 14 +- internal/services/config/config_test.go | 2 +- .../services/configstore/action/action.go | 6 +- .../configstore/action/maintenance.go | 13 +- internal/services/configstore/action/org.go | 59 ++-- .../services/configstore/action/project.go | 57 ++-- .../configstore/action/projectgroup.go | 63 ++-- .../configstore/action/remotesource.go | 37 ++- .../services/configstore/action/secret.go | 53 +-- internal/services/configstore/action/user.go | 101 +++--- .../services/configstore/action/variable.go | 49 +-- internal/services/configstore/api/api.go | 6 +- internal/services/configstore/api/org.go | 8 +- internal/services/configstore/api/project.go | 16 +- .../services/configstore/api/projectgroup.go | 12 +- .../services/configstore/api/remotesource.go | 6 +- internal/services/configstore/api/secret.go | 6 +- internal/services/configstore/api/user.go | 14 +- internal/services/configstore/api/variable.go | 6 +- .../services/configstore/common/common.go | 3 +- internal/services/configstore/configstore.go | 24 +- .../services/configstore/configstore_test.go | 14 +- internal/services/configstore/readdb/org.go | 88 ++--- .../services/configstore/readdb/project.go | 52 +-- .../configstore/readdb/projectgroup.go | 52 +-- .../services/configstore/readdb/readdb.go | 186 +++++------ .../configstore/readdb/remotesource.go | 42 +-- .../services/configstore/readdb/resolve.go | 44 ++- .../services/configstore/readdb/secret.go | 46 +-- internal/services/configstore/readdb/user.go | 78 ++--- .../services/configstore/readdb/variable.go | 40 +-- internal/services/executor/api.go | 18 +- internal/services/executor/driver/docker.go | 63 ++-- internal/services/executor/driver/driver.go | 3 +- internal/services/executor/driver/k8s.go | 76 ++--- internal/services/executor/driver/k8slease.go | 30 +- internal/services/executor/executor.go | 168 +++++----- .../services/executor/registry/registry.go | 16 +- internal/services/gateway/action/auth.go | 21 +- internal/services/gateway/action/org.go | 17 +- internal/services/gateway/action/project.go | 101 +++--- .../services/gateway/action/projectgroup.go | 21 +- .../services/gateway/action/remotesource.go | 15 +- internal/services/gateway/action/run.go | 31 +- internal/services/gateway/action/secret.go | 15 +- internal/services/gateway/action/user.go | 119 +++---- internal/services/gateway/action/variable.go | 26 +- internal/services/gateway/api/api.go | 6 +- internal/services/gateway/api/org.go | 4 +- internal/services/gateway/api/projectgroup.go | 2 +- internal/services/gateway/api/remoterepo.go | 4 +- internal/services/gateway/api/remotesource.go | 4 +- internal/services/gateway/api/run.go | 12 +- internal/services/gateway/api/user.go | 12 +- internal/services/gateway/api/webhook.go | 14 +- internal/services/gateway/gateway.go | 16 +- internal/services/gateway/handlers/auth.go | 2 +- internal/services/gitserver/gitserver_test.go | 2 +- internal/services/gitserver/main.go | 20 +- internal/services/gitserver/repo-cleaner.go | 35 +- .../services/notification/commitstatus.go | 21 +- .../services/notification/notification.go | 4 +- internal/services/notification/runevents.go | 12 +- internal/services/runservice/action/action.go | 79 +++-- .../services/runservice/action/maintenance.go | 13 +- internal/services/runservice/api/api.go | 64 ++-- internal/services/runservice/api/executor.go | 16 +- internal/services/runservice/common/common.go | 10 +- internal/services/runservice/common/events.go | 3 +- internal/services/runservice/readdb/readdb.go | 310 +++++++++--------- internal/services/runservice/runservice.go | 24 +- internal/services/runservice/scheduler.go | 156 ++++----- internal/services/runservice/store/store.go | 85 ++--- .../services/runservice/store/store_test.go | 9 +- internal/services/scheduler/scheduler.go | 16 +- internal/testutil/env.go | 11 +- internal/testutil/utils.go | 68 ++-- internal/toolbox/archive/archive.go | 34 +- internal/toolbox/unarchive/unarchive.go | 60 ++-- internal/util/backoff.go | 5 +- internal/util/buffer.go | 8 +- internal/util/errors.go | 7 +- internal/util/git.go | 31 +- internal/util/http.go | 8 +- internal/util/password.go | 8 +- internal/util/ssh.go | 6 +- internal/util/string.go | 4 +- internal/util/tls.go | 8 +- internal/util/validation.go | 3 +- services/configstore/client/client.go | 145 ++++---- services/configstore/types/types.go | 6 +- services/gateway/client/client.go | 139 ++++---- services/runservice/client/client.go | 37 ++- services/runservice/types/types.go | 21 +- tests/setup_test.go | 18 +- 183 files changed, 2912 insertions(+), 2348 deletions(-) create mode 100644 internal/errors/errors.go create mode 100644 internal/errors/format.go create mode 100644 internal/errors/go113.go create mode 100644 internal/errors/stack.go create mode 100644 internal/errors/zerolog.go diff --git a/.golangci.yml b/.golangci.yml index 0ed3153..01c698b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,2 +1,25 @@ linters: - enable: errorlint + enable: + - errorlint + - wrapcheck + +linters-settings: + wrapcheck: + # An array of strings that specify substrings of signatures to ignore. + # If this set, it will override the default set of ignored signatures. + # See https://github.com/tomarrell/wrapcheck#configuration for more information. + ignoreSigs: + - .Errorf( + - errors.New( + - errors.Unwrap( + - .Wrap( + - .Wrapf( + - .WithMessage( + - .WithMessagef( + - .WithStack( + - .NewDetailedError( + ignoreSigRegexps: + - \.New.*Error\( + ignorePackageGlobs: + - encoding/* + - github.com/pkg/* diff --git a/cmd/agola/cmd/agola.go b/cmd/agola/cmd/agola.go index 204bcf8..5f10300 100644 --- a/cmd/agola/cmd/agola.go +++ b/cmd/agola/cmd/agola.go @@ -20,19 +20,20 @@ import ( "time" "agola.io/agola/cmd" + "agola.io/agola/internal/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var token string func init() { cw := zerolog.ConsoleWriter{ - Out: os.Stderr, - TimeFormat: time.RFC3339Nano, + Out: os.Stderr, + TimeFormat: time.RFC3339Nano, + FormatErrFieldValue: errors.FormatErrFieldValue, } zerolog.TimeFieldFormat = time.RFC3339Nano @@ -53,6 +54,9 @@ var cmdAgola = &cobra.Command{ if agolaOpts.debug { log.Logger = log.Level(zerolog.DebugLevel) } + if agolaOpts.detailedErrors { + zerolog.ErrorMarshalFunc = errors.ErrorMarshalFunc + } }, Run: func(c *cobra.Command, args []string) { if err := c.Help(); err != nil { @@ -62,8 +66,9 @@ var cmdAgola = &cobra.Command{ } type agolaOptions struct { - gatewayURL string - debug bool + gatewayURL string + debug bool + detailedErrors bool } var agolaOpts agolaOptions @@ -84,6 +89,7 @@ func init() { flags.StringVarP(&agolaOpts.gatewayURL, "gateway-url", "u", gatewayURL, "agola gateway exposed url") flags.StringVar(&token, "token", token, "api token") flags.BoolVarP(&agolaOpts.debug, "debug", "d", false, "debug") + flags.BoolVar(&agolaOpts.detailedErrors, "detailed-errors", false, "enabled detailed errors logging") } func Execute() { diff --git a/cmd/agola/cmd/completion.go b/cmd/agola/cmd/completion.go index d2a4ae8..6dafcca 100644 --- a/cmd/agola/cmd/completion.go +++ b/cmd/agola/cmd/completion.go @@ -17,6 +17,7 @@ package cmd import ( "os" + "agola.io/agola/internal/errors" "github.com/spf13/cobra" ) @@ -33,11 +34,11 @@ func completionShell(cmd *cobra.Command, args []string, shell string) error { switch shell { case "bash": if err := cmdAgola.GenBashCompletion(os.Stdout); err != nil { - return err + return errors.WithStack(err) } case "zsh": if err := cmdAgola.GenZshCompletion(os.Stdout); err != nil { - return err + return errors.WithStack(err) } } return nil diff --git a/cmd/agola/cmd/directrunstart.go b/cmd/agola/cmd/directrunstart.go index a23b2a5..2d392b0 100644 --- a/cmd/agola/cmd/directrunstart.go +++ b/cmd/agola/cmd/directrunstart.go @@ -23,6 +23,7 @@ import ( "strings" "unicode" + "agola.io/agola/internal/errors" gitsave "agola.io/agola/internal/git-save" "agola.io/agola/internal/util" gwapitypes "agola.io/agola/services/gateway/api/types" @@ -32,7 +33,6 @@ import ( "github.com/gofrs/uuid" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdDirectRunStart = &cobra.Command{ @@ -80,15 +80,15 @@ func parseVariable(variable string) (string, string, error) { variable = strings.TrimLeftFunc(variable, unicode.IsSpace) arr := strings.SplitN(variable, "=", 2) if len(arr) != 2 { - return "", "", fmt.Errorf("invalid variable definition: %s", variable) + return "", "", errors.Errorf("invalid variable definition: %s", variable) } varname := arr[0] varvalue := arr[1] if varname == "" { - return "", "", fmt.Errorf("invalid variable definition: %s", variable) + return "", "", errors.Errorf("invalid variable definition: %s", variable) } if varvalue == "" { - return "", "", fmt.Errorf("invalid variable definition: %s", variable) + return "", "", errors.Errorf("invalid variable definition: %s", variable) } return varname, varvalue, nil } @@ -98,7 +98,7 @@ func directRunStart(cmd *cobra.Command, args []string) error { for _, res := range directRunStartOpts.prRefRegexes { if _, err := regexp.Compile(res); err != nil { - return fmt.Errorf("wrong regular expression %q: %w", res, err) + return errors.Wrapf(err, "wrong regular expression %q", res) } } @@ -123,12 +123,12 @@ func directRunStart(cmd *cobra.Command, args []string) error { branch = "" } if set > 1 { - return fmt.Errorf(`only one of "--branch", "--tag" or "--ref" can be provided`) + return errors.Errorf(`only one of "--branch", "--tag" or "--ref" can be provided`) } user, _, err := gwclient.GetCurrentUser(context.TODO()) if err != nil { - return err + return errors.WithStack(err) } variables := map[string]string{} @@ -142,11 +142,11 @@ func directRunStart(cmd *cobra.Command, args []string) error { var err error data, err = ioutil.ReadFile(varFile) if err != nil { - return err + return errors.WithStack(err) } if err := yaml.Unmarshal(data, &variables); err != nil { - return errors.Errorf("failed to unmarshal values: %w", err) + return errors.Wrapf(err, "failed to unmarshal values") } // TODO(sgotti) validate variable name @@ -155,7 +155,7 @@ func directRunStart(cmd *cobra.Command, args []string) error { for _, variable := range directRunStartOpts.vars { varname, varvalue, err := parseVariable(variable) if err != nil { - return err + return errors.WithStack(err) } variables[varname] = varvalue } @@ -166,7 +166,7 @@ func directRunStart(cmd *cobra.Command, args []string) error { if repoUUID == "" { repoUUID = uuid.Must(uuid.NewV4()).String() if _, err := git.ConfigSet(context.Background(), "agola.repouuid", repoUUID); err != nil { - return fmt.Errorf("failed to set agola repo uid in git config: %w", err) + return errors.Wrapf(err, "failed to set agola repo uid in git config") } } @@ -180,7 +180,7 @@ func directRunStart(cmd *cobra.Command, args []string) error { commitSHA, err := gs.Save(message, localBranch) if err != nil { - return err + return errors.WithStack(err) } log.Info().Msgf("pushing branch") @@ -190,15 +190,15 @@ func directRunStart(cmd *cobra.Command, args []string) error { // push to a branch with default branch refs "refs/heads/branch" if branch != "" { if err := gitsave.GitPush("", repoURL, fmt.Sprintf("%s:refs/heads/%s", path.Join(gs.RefsPrefix(), localBranch), branch)); err != nil { - return err + return errors.WithStack(err) } } else if tag != "" { if err := gitsave.GitPush("", repoURL, fmt.Sprintf("%s:refs/tags/%s", path.Join(gs.RefsPrefix(), localBranch), tag)); err != nil { - return err + return errors.WithStack(err) } } else if ref != "" { if err := gitsave.GitPush("", repoURL, fmt.Sprintf("%s:%s", path.Join(gs.RefsPrefix(), localBranch), ref)); err != nil { - return err + return errors.WithStack(err) } } @@ -215,7 +215,7 @@ func directRunStart(cmd *cobra.Command, args []string) error { Variables: variables, } if _, err := gwclient.UserCreateRun(context.TODO(), req); err != nil { - return err + return errors.WithStack(err) } return nil diff --git a/cmd/agola/cmd/logdelete.go b/cmd/agola/cmd/logdelete.go index dae9f6c..2d9da85 100644 --- a/cmd/agola/cmd/logdelete.go +++ b/cmd/agola/cmd/logdelete.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdLogDelete = &cobra.Command{ @@ -93,7 +93,7 @@ func logDelete(cmd *cobra.Command, args []string) error { run, _, err := gwclient.GetRun(context.TODO(), logDeleteOpts.runid) if err != nil { - return err + return errors.WithStack(err) } for _, t := range run.Tasks { if t.Name == logDeleteOpts.taskname { diff --git a/cmd/agola/cmd/logget.go b/cmd/agola/cmd/logget.go index 4a7ee38..bec5cdc 100644 --- a/cmd/agola/cmd/logget.go +++ b/cmd/agola/cmd/logget.go @@ -19,12 +19,12 @@ import ( "io" "os" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdLogGet = &cobra.Command{ @@ -102,7 +102,7 @@ func logGet(cmd *cobra.Command, args []string) error { run, _, err := gwclient.GetRun(context.TODO(), logGetOpts.runid) if err != nil { - return err + return errors.WithStack(err) } for _, t := range run.Tasks { if t.Name == logGetOpts.taskname { @@ -127,7 +127,7 @@ func logGet(cmd *cobra.Command, args []string) error { if flags.Changed("output") { f, err := os.Create(logGetOpts.output) if err != nil { - return err + return errors.WithStack(err) } defer f.Close() if _, err := io.Copy(f, resp.Body); err != nil { diff --git a/cmd/agola/cmd/orgcreate.go b/cmd/agola/cmd/orgcreate.go index d8be957..a09bc98 100644 --- a/cmd/agola/cmd/orgcreate.go +++ b/cmd/agola/cmd/orgcreate.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdOrgCreate = &cobra.Command{ @@ -71,7 +71,7 @@ func orgCreate(cmd *cobra.Command, args []string) error { log.Info().Msgf("creating org") org, _, err := gwclient.CreateOrg(context.TODO(), req) if err != nil { - return errors.Errorf("failed to create org: %w", err) + return errors.Wrapf(err, "failed to create org") } log.Info().Msgf("org %q created, ID: %q", org.Name, org.ID) diff --git a/cmd/agola/cmd/orgdelete.go b/cmd/agola/cmd/orgdelete.go index e831ef3..119c371 100644 --- a/cmd/agola/cmd/orgdelete.go +++ b/cmd/agola/cmd/orgdelete.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdOrgDelete = &cobra.Command{ @@ -57,7 +57,7 @@ func orgDelete(cmd *cobra.Command, args []string) error { log.Info().Msgf("deleting organization %q", orgDeleteOpts.name) if _, err := gwclient.DeleteOrg(context.TODO(), orgDeleteOpts.name); err != nil { - return errors.Errorf("failed to delete organization: %w", err) + return errors.Wrapf(err, "failed to delete organization") } return nil diff --git a/cmd/agola/cmd/orgmemberadd.go b/cmd/agola/cmd/orgmemberadd.go index 345ee63..041167c 100644 --- a/cmd/agola/cmd/orgmemberadd.go +++ b/cmd/agola/cmd/orgmemberadd.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdOrgMemberAdd = &cobra.Command{ @@ -66,7 +66,7 @@ func orgMemberAdd(cmd *cobra.Command, args []string) error { log.Info().Msgf("adding/updating member %q to organization %q with role %q", orgMemberAddOpts.username, orgMemberAddOpts.orgname, orgMemberAddOpts.role) _, _, err := gwclient.AddOrgMember(context.TODO(), orgMemberAddOpts.orgname, orgMemberAddOpts.username, gwapitypes.MemberRole(orgMemberAddOpts.role)) if err != nil { - return errors.Errorf("failed to add/update organization member: %w", err) + return errors.Wrapf(err, "failed to add/update organization member") } return nil diff --git a/cmd/agola/cmd/orgmemberlist.go b/cmd/agola/cmd/orgmemberlist.go index 4149d0f..eaade53 100644 --- a/cmd/agola/cmd/orgmemberlist.go +++ b/cmd/agola/cmd/orgmemberlist.go @@ -19,11 +19,11 @@ import ( "encoding/json" "os" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdOrgMemberList = &cobra.Command{ @@ -59,12 +59,12 @@ func orgMemberList(cmd *cobra.Command, args []string) error { orgMembers, _, err := gwclient.GetOrgMembers(context.TODO(), orgMemberListOpts.orgname) if err != nil { - return errors.Errorf("failed to get organization member: %w", err) + return errors.Wrapf(err, "failed to get organization member") } out, err := json.MarshalIndent(orgMembers, "", "\t") if err != nil { - return err + return errors.WithStack(err) } os.Stdout.Write(out) diff --git a/cmd/agola/cmd/orgmemberremove.go b/cmd/agola/cmd/orgmemberremove.go index 8619368..6536f53 100644 --- a/cmd/agola/cmd/orgmemberremove.go +++ b/cmd/agola/cmd/orgmemberremove.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdOrgMemberRemove = &cobra.Command{ @@ -63,7 +63,7 @@ func orgMemberRemove(cmd *cobra.Command, args []string) error { log.Info().Msgf("removing member %q from organization %q", orgMemberRemoveOpts.username, orgMemberRemoveOpts.orgname) _, err := gwclient.RemoveOrgMember(context.TODO(), orgMemberRemoveOpts.orgname, orgMemberRemoveOpts.username) if err != nil { - return errors.Errorf("failed to remove organization member: %w", err) + return errors.Wrapf(err, "failed to remove organization member") } return nil diff --git a/cmd/agola/cmd/projectcreate.go b/cmd/agola/cmd/projectcreate.go index 7b6405d..99bb619 100644 --- a/cmd/agola/cmd/projectcreate.go +++ b/cmd/agola/cmd/projectcreate.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectCreate = &cobra.Command{ @@ -106,7 +106,7 @@ func projectCreate(cmd *cobra.Command, args []string) error { project, _, err := gwclient.CreateProject(context.TODO(), req) if err != nil { - return errors.Errorf("failed to create project: %w", err) + return errors.Wrapf(err, "failed to create project") } log.Info().Msgf("project %s created, ID: %s", project.Name, project.ID) diff --git a/cmd/agola/cmd/projectdelete.go b/cmd/agola/cmd/projectdelete.go index c6f2576..2300f03 100644 --- a/cmd/agola/cmd/projectdelete.go +++ b/cmd/agola/cmd/projectdelete.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectDelete = &cobra.Command{ @@ -58,7 +58,7 @@ func projectDelete(cmd *cobra.Command, args []string) error { log.Info().Msgf("deleting project") if _, err := gwclient.DeleteProject(context.TODO(), projectDeleteOpts.ref); err != nil { - return errors.Errorf("failed to delete project: %w", err) + return errors.Wrapf(err, "failed to delete project") } return nil diff --git a/cmd/agola/cmd/projectgroupcreate.go b/cmd/agola/cmd/projectgroupcreate.go index 4067e1c..7b99c24 100644 --- a/cmd/agola/cmd/projectgroupcreate.go +++ b/cmd/agola/cmd/projectgroupcreate.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectGroupCreate = &cobra.Command{ @@ -78,7 +78,7 @@ func projectGroupCreate(cmd *cobra.Command, args []string) error { projectGroup, _, err := gwclient.CreateProjectGroup(context.TODO(), req) if err != nil { - return errors.Errorf("failed to create project group: %w", err) + return errors.Wrapf(err, "failed to create project group") } log.Info().Msgf("project group %s created, ID: %s", projectGroup.Name, projectGroup.ID) diff --git a/cmd/agola/cmd/projectgroupdelete.go b/cmd/agola/cmd/projectgroupdelete.go index 0d421e1..cef9e5a 100644 --- a/cmd/agola/cmd/projectgroupdelete.go +++ b/cmd/agola/cmd/projectgroupdelete.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectGroupDelete = &cobra.Command{ @@ -58,7 +58,7 @@ func projectGroupDelete(cmd *cobra.Command, args []string) error { log.Info().Msgf("deleting project group") if _, err := gwclient.DeleteProjectGroup(context.TODO(), projectGroupDeleteOpts.ref); err != nil { - return errors.Errorf("failed to delete project group: %w", err) + return errors.Wrapf(err, "failed to delete project group") } return nil diff --git a/cmd/agola/cmd/projectgroupupdate.go b/cmd/agola/cmd/projectgroupupdate.go index 4985d90..abf1b88 100644 --- a/cmd/agola/cmd/projectgroupupdate.go +++ b/cmd/agola/cmd/projectgroupupdate.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectGroupUpdate = &cobra.Command{ @@ -82,7 +82,7 @@ func projectGroupUpdate(cmd *cobra.Command, args []string) error { log.Info().Msgf("updating project group") projectGroup, _, err := gwclient.UpdateProjectGroup(context.TODO(), projectGroupUpdateOpts.ref, req) if err != nil { - return errors.Errorf("failed to update project group: %w", err) + return errors.Wrapf(err, "failed to update project group") } log.Info().Msgf("project group %s update, ID: %s", projectGroup.Name, projectGroup.ID) diff --git a/cmd/agola/cmd/projectlist.go b/cmd/agola/cmd/projectlist.go index fa21472..29c378e 100644 --- a/cmd/agola/cmd/projectlist.go +++ b/cmd/agola/cmd/projectlist.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" @@ -64,7 +65,7 @@ func projectList(cmd *cobra.Command, args []string) error { projects, _, err := gwclient.GetProjectGroupProjects(context.TODO(), projectListOpts.parentPath) if err != nil { - return err + return errors.WithStack(err) } printProjects(projects) diff --git a/cmd/agola/cmd/projectreconfig.go b/cmd/agola/cmd/projectreconfig.go index 022c4d8..65e98c2 100644 --- a/cmd/agola/cmd/projectreconfig.go +++ b/cmd/agola/cmd/projectreconfig.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectReconfig = &cobra.Command{ @@ -57,7 +57,7 @@ func projectReconfig(cmd *cobra.Command, args []string) error { log.Info().Msgf("reconfiguring remote project") if _, err := gwclient.ReconfigProject(context.TODO(), projectReconfigOpts.name); err != nil { - return errors.Errorf("failed to reconfigure remote project: %w", err) + return errors.Wrapf(err, "failed to reconfigure remote project") } log.Info().Msgf("project reconfigured") diff --git a/cmd/agola/cmd/projectsecretcreate.go b/cmd/agola/cmd/projectsecretcreate.go index 4818d2e..8a284bd 100644 --- a/cmd/agola/cmd/projectsecretcreate.go +++ b/cmd/agola/cmd/projectsecretcreate.go @@ -19,13 +19,13 @@ import ( "io/ioutil" "os" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/ghodss/yaml" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectSecretCreate = &cobra.Command{ @@ -82,12 +82,12 @@ func secretCreate(cmd *cobra.Command, ownertype string, args []string) error { if secretCreateOpts.file == "-" { data, err = ioutil.ReadAll(os.Stdin) if err != nil { - return err + return errors.WithStack(err) } } else { data, err = ioutil.ReadFile(secretCreateOpts.file) if err != nil { - return err + return errors.WithStack(err) } } @@ -106,14 +106,14 @@ func secretCreate(cmd *cobra.Command, ownertype string, args []string) error { log.Info().Msgf("creating project secret") secret, _, err := gwclient.CreateProjectSecret(context.TODO(), secretCreateOpts.parentRef, req) if err != nil { - return errors.Errorf("failed to create project secret: %w", err) + return errors.Wrapf(err, "failed to create project secret") } log.Info().Msgf("project secret %q created, ID: %q", secret.Name, secret.ID) case "projectgroup": log.Info().Msgf("creating project group secret") secret, _, err := gwclient.CreateProjectGroupSecret(context.TODO(), secretCreateOpts.parentRef, req) if err != nil { - return errors.Errorf("failed to create project group secret: %w", err) + return errors.Wrapf(err, "failed to create project group secret") } log.Info().Msgf("project group secret %q created, ID: %q", secret.Name, secret.ID) } diff --git a/cmd/agola/cmd/projectsecretdelete.go b/cmd/agola/cmd/projectsecretdelete.go index 6a0d85f..399d13b 100644 --- a/cmd/agola/cmd/projectsecretdelete.go +++ b/cmd/agola/cmd/projectsecretdelete.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectSecretDelete = &cobra.Command{ @@ -65,14 +65,14 @@ func secretDelete(cmd *cobra.Command, ownertype string, args []string) error { log.Info().Msgf("deleting project secret") _, err := gwclient.DeleteProjectSecret(context.TODO(), secretDeleteOpts.parentRef, secretDeleteOpts.name) if err != nil { - return errors.Errorf("failed to delete project secret: %w", err) + return errors.Wrapf(err, "failed to delete project secret") } log.Info().Msgf("project secret deleted") case "projectgroup": log.Info().Msgf("deleting project group secret") _, err := gwclient.DeleteProjectGroupSecret(context.TODO(), secretDeleteOpts.parentRef, secretDeleteOpts.name) if err != nil { - return errors.Errorf("failed to delete project group secret: %w", err) + return errors.Wrapf(err, "failed to delete project group secret") } log.Info().Msgf("project group secret deleted") } diff --git a/cmd/agola/cmd/projectsecretlist.go b/cmd/agola/cmd/projectsecretlist.go index b77c750..d5dc185 100644 --- a/cmd/agola/cmd/projectsecretlist.go +++ b/cmd/agola/cmd/projectsecretlist.go @@ -19,12 +19,12 @@ import ( "encoding/json" "fmt" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectSecretList = &cobra.Command{ @@ -57,10 +57,10 @@ func init() { func secretList(cmd *cobra.Command, ownertype string, args []string) error { if err := printSecrets(ownertype, fmt.Sprintf("%s secrets", ownertype), false, false); err != nil { - return err + return errors.WithStack(err) } if err := printSecrets(ownertype, "All secrets (local and inherited)", true, true); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -79,11 +79,11 @@ func printSecrets(ownertype, description string, tree, removeoverridden bool) er secrets, _, err = gwclient.GetProjectGroupSecrets(context.TODO(), secretListOpts.parentRef, tree, removeoverridden) } if err != nil { - return errors.Errorf("failed to list %s secrets: %w", ownertype, err) + return errors.Wrapf(err, "failed to list %s secrets", ownertype) } prettyJSON, err := json.MarshalIndent(secrets, "", "\t") if err != nil { - return errors.Errorf("failed to convert %s secrets to json: %w", ownertype, err) + return errors.Wrapf(err, "failed to convert %s secrets to json", ownertype) } fmt.Printf("%s:\n%s\n", description, string(prettyJSON)) return nil diff --git a/cmd/agola/cmd/projectsecretupdate.go b/cmd/agola/cmd/projectsecretupdate.go index fd30705..3d94ccf 100644 --- a/cmd/agola/cmd/projectsecretupdate.go +++ b/cmd/agola/cmd/projectsecretupdate.go @@ -19,13 +19,13 @@ import ( "io/ioutil" "os" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/ghodss/yaml" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectSecretUpdate = &cobra.Command{ @@ -84,12 +84,12 @@ func secretUpdate(cmd *cobra.Command, ownertype string, args []string) error { if secretUpdateOpts.file == "-" { data, err = ioutil.ReadAll(os.Stdin) if err != nil { - return err + return errors.WithStack(err) } } else { data, err = ioutil.ReadFile(secretUpdateOpts.file) if err != nil { - return err + return errors.WithStack(err) } } @@ -113,14 +113,14 @@ func secretUpdate(cmd *cobra.Command, ownertype string, args []string) error { log.Info().Msgf("creating project secret") secret, _, err := gwclient.UpdateProjectSecret(context.TODO(), secretUpdateOpts.parentRef, secretUpdateOpts.name, req) if err != nil { - return errors.Errorf("failed to update project secret: %w", err) + return errors.Wrapf(err, "failed to update project secret") } log.Info().Msgf("project secret %q updated, ID: %q", secret.Name, secret.ID) case "projectgroup": log.Info().Msgf("creating project group secret") secret, _, err := gwclient.UpdateProjectGroupSecret(context.TODO(), secretUpdateOpts.parentRef, secretUpdateOpts.name, req) if err != nil { - return errors.Errorf("failed to update project group secret: %w", err) + return errors.Wrapf(err, "failed to update project group secret") } log.Info().Msgf("project group secret %q updated, ID: %q", secret.Name, secret.ID) } diff --git a/cmd/agola/cmd/projectupdate.go b/cmd/agola/cmd/projectupdate.go index 168b7b9..38ab949 100644 --- a/cmd/agola/cmd/projectupdate.go +++ b/cmd/agola/cmd/projectupdate.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectUpdate = &cobra.Command{ @@ -88,7 +88,7 @@ func projectUpdate(cmd *cobra.Command, args []string) error { log.Info().Msgf("updating project") project, _, err := gwclient.UpdateProject(context.TODO(), projectUpdateOpts.ref, req) if err != nil { - return errors.Errorf("failed to update project: %w", err) + return errors.Wrapf(err, "failed to update project") } log.Info().Msgf("project %s update, ID: %s", project.Name, project.ID) diff --git a/cmd/agola/cmd/projectvariablecreate.go b/cmd/agola/cmd/projectvariablecreate.go index dfef1ea..3e7e36f 100644 --- a/cmd/agola/cmd/projectvariablecreate.go +++ b/cmd/agola/cmd/projectvariablecreate.go @@ -20,13 +20,13 @@ import ( "os" config "agola.io/agola/internal/config" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/ghodss/yaml" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectVariableCreate = &cobra.Command{ @@ -105,12 +105,12 @@ func variableCreate(cmd *cobra.Command, ownertype string, args []string) error { if variableCreateOpts.file == "-" { data, err = ioutil.ReadAll(os.Stdin) if err != nil { - return err + return errors.WithStack(err) } } else { data, err = ioutil.ReadFile(variableCreateOpts.file) if err != nil { - return err + return errors.WithStack(err) } } @@ -136,14 +136,14 @@ func variableCreate(cmd *cobra.Command, ownertype string, args []string) error { log.Info().Msgf("creating project variable") variable, _, err := gwclient.CreateProjectVariable(context.TODO(), variableCreateOpts.parentRef, req) if err != nil { - return errors.Errorf("failed to create project variable: %w", err) + return errors.Wrapf(err, "failed to create project variable") } log.Info().Msgf("project variable %q created, ID: %q", variable.Name, variable.ID) case "projectgroup": log.Info().Msgf("creating project group variable") variable, _, err := gwclient.CreateProjectGroupVariable(context.TODO(), variableCreateOpts.parentRef, req) if err != nil { - return errors.Errorf("failed to create project group variable: %w", err) + return errors.Wrapf(err, "failed to create project group variable") } log.Info().Msgf("project group variable %q created, ID: %q", variable.Name, variable.ID) } diff --git a/cmd/agola/cmd/projectvariabledelete.go b/cmd/agola/cmd/projectvariabledelete.go index d75b320..853317d 100644 --- a/cmd/agola/cmd/projectvariabledelete.go +++ b/cmd/agola/cmd/projectvariabledelete.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectVariableDelete = &cobra.Command{ @@ -65,14 +65,14 @@ func variableDelete(cmd *cobra.Command, ownertype string, args []string) error { log.Info().Msgf("deleting project variable") _, err := gwclient.DeleteProjectVariable(context.TODO(), variableDeleteOpts.parentRef, variableDeleteOpts.name) if err != nil { - return errors.Errorf("failed to delete project variable: %w", err) + return errors.Wrapf(err, "failed to delete project variable") } log.Info().Msgf("project variable deleted") case "projectgroup": log.Info().Msgf("deleting project group variable") _, err := gwclient.DeleteProjectGroupVariable(context.TODO(), variableDeleteOpts.parentRef, variableDeleteOpts.name) if err != nil { - return errors.Errorf("failed to delete project group variable: %w", err) + return errors.Wrapf(err, "failed to delete project group variable") } log.Info().Msgf("project group variable deleted") } diff --git a/cmd/agola/cmd/projectvariablelist.go b/cmd/agola/cmd/projectvariablelist.go index 6779140..074aafd 100644 --- a/cmd/agola/cmd/projectvariablelist.go +++ b/cmd/agola/cmd/projectvariablelist.go @@ -19,12 +19,12 @@ import ( "encoding/json" "fmt" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectVariableList = &cobra.Command{ @@ -57,10 +57,10 @@ func init() { func variableList(cmd *cobra.Command, ownertype string, args []string) error { if err := printVariables(ownertype, fmt.Sprintf("%s variables", ownertype), false, false); err != nil { - return err + return errors.WithStack(err) } if err := printVariables(ownertype, "All variables (local and inherited)", true, true); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -79,11 +79,11 @@ func printVariables(ownertype, description string, tree, removeoverridden bool) variables, _, err = gwclient.GetProjectGroupVariables(context.TODO(), variableListOpts.parentRef, tree, removeoverridden) } if err != nil { - return errors.Errorf("failed to list %s variables: %w", ownertype, err) + return errors.Wrapf(err, "failed to list %s variables", ownertype) } prettyJSON, err := json.MarshalIndent(variables, "", "\t") if err != nil { - return errors.Errorf("failed to convert %s variables to json: %w", ownertype, err) + return errors.Wrapf(err, "failed to convert %s variables to json", ownertype) } fmt.Printf("%s:\n%s\n", description, string(prettyJSON)) return nil diff --git a/cmd/agola/cmd/projectvariableupdate.go b/cmd/agola/cmd/projectvariableupdate.go index 9cec37d..58678f9 100644 --- a/cmd/agola/cmd/projectvariableupdate.go +++ b/cmd/agola/cmd/projectvariableupdate.go @@ -19,13 +19,13 @@ import ( "io/ioutil" "os" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/ghodss/yaml" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdProjectVariableUpdate = &cobra.Command{ @@ -77,12 +77,12 @@ func variableUpdate(cmd *cobra.Command, ownertype string, args []string) error { if variableUpdateOpts.file == "-" { data, err = ioutil.ReadAll(os.Stdin) if err != nil { - return err + return errors.WithStack(err) } } else { data, err = ioutil.ReadFile(variableUpdateOpts.file) if err != nil { - return err + return errors.WithStack(err) } } @@ -113,14 +113,14 @@ func variableUpdate(cmd *cobra.Command, ownertype string, args []string) error { log.Info().Msgf("updating project variable") variable, _, err := gwclient.UpdateProjectVariable(context.TODO(), variableUpdateOpts.parentRef, variableUpdateOpts.name, req) if err != nil { - return errors.Errorf("failed to update project variable: %w", err) + return errors.Wrapf(err, "failed to update project variable") } log.Info().Msgf("project variable %q updated, ID: %q", variable.Name, variable.ID) case "projectgroup": log.Info().Msgf("updating project group variable") variable, _, err := gwclient.UpdateProjectGroupVariable(context.TODO(), variableUpdateOpts.parentRef, variableUpdateOpts.name, req) if err != nil { - return errors.Errorf("failed to update project group variable: %w", err) + return errors.Wrapf(err, "failed to update project group variable") } log.Info().Msgf("project group variable %q updated, ID: %q", variable.Name, variable.ID) } diff --git a/cmd/agola/cmd/remotesourcecreate.go b/cmd/agola/cmd/remotesourcecreate.go index 2c34d6e..4daa667 100644 --- a/cmd/agola/cmd/remotesourcecreate.go +++ b/cmd/agola/cmd/remotesourcecreate.go @@ -17,6 +17,7 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" "agola.io/agola/internal/gitsources/github" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" @@ -24,7 +25,6 @@ import ( "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdRemoteSourceCreate = &cobra.Command{ @@ -117,7 +117,7 @@ func remoteSourceCreate(cmd *cobra.Command, args []string) error { log.Info().Msgf("creating remotesource") remoteSource, _, err := gwclient.CreateRemoteSource(context.TODO(), req) if err != nil { - return errors.Errorf("failed to create remotesource: %w", err) + return errors.Wrapf(err, "failed to create remotesource") } log.Info().Msgf("remotesource %s created, ID: %s", remoteSource.Name, remoteSource.ID) diff --git a/cmd/agola/cmd/remotesourcelist.go b/cmd/agola/cmd/remotesourcelist.go index 7d152f6..3a6c3fe 100644 --- a/cmd/agola/cmd/remotesourcelist.go +++ b/cmd/agola/cmd/remotesourcelist.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" @@ -62,7 +63,7 @@ func remoteSourceList(cmd *cobra.Command, args []string) error { remouteSources, _, err := gwclient.GetRemoteSources(context.TODO(), remoteSourceListOpts.start, remoteSourceListOpts.limit, false) if err != nil { - return err + return errors.WithStack(err) } printRemoteSources(remouteSources) diff --git a/cmd/agola/cmd/remotesourceupdate.go b/cmd/agola/cmd/remotesourceupdate.go index fb925d9..c3b7496 100644 --- a/cmd/agola/cmd/remotesourceupdate.go +++ b/cmd/agola/cmd/remotesourceupdate.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdRemoteSourceUpdate = &cobra.Command{ @@ -109,7 +109,7 @@ func remoteSourceUpdate(cmd *cobra.Command, args []string) error { log.Info().Msgf("updating remotesource") remoteSource, _, err := gwclient.UpdateRemoteSource(context.TODO(), remoteSourceUpdateOpts.ref, req) if err != nil { - return errors.Errorf("failed to update remotesource: %w", err) + return errors.Wrapf(err, "failed to update remotesource") } log.Info().Msgf("remotesource %s updated, ID: %s", remoteSource.Name, remoteSource.ID) diff --git a/cmd/agola/cmd/runcreate.go b/cmd/agola/cmd/runcreate.go index 2d34510..d18977e 100644 --- a/cmd/agola/cmd/runcreate.go +++ b/cmd/agola/cmd/runcreate.go @@ -16,8 +16,8 @@ package cmd import ( "context" - "fmt" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" @@ -76,7 +76,7 @@ func runCreate(cmd *cobra.Command, args []string) error { set++ } if set != 1 { - return fmt.Errorf(`one of "--branch", "--tag" or "--ref" must be provided`) + return errors.Errorf(`one of "--branch", "--tag" or "--ref" must be provided`) } req := &gwapitypes.ProjectCreateRunRequest{ @@ -88,5 +88,5 @@ func runCreate(cmd *cobra.Command, args []string) error { _, err := gwclient.ProjectCreateRun(context.TODO(), runCreateOpts.projectRef, req) - return err + return errors.WithStack(err) } diff --git a/cmd/agola/cmd/runlist.go b/cmd/agola/cmd/runlist.go index 0ec26b8..7a94e85 100644 --- a/cmd/agola/cmd/runlist.go +++ b/cmd/agola/cmd/runlist.go @@ -20,9 +20,9 @@ import ( "path" "sort" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" - errors "golang.org/x/xerrors" "github.com/rs/zerolog/log" "github.com/spf13/cobra" @@ -104,14 +104,14 @@ func runList(cmd *cobra.Command, args []string) error { groups := []string{path.Join("/project", project.ID)} runsResp, _, err := gwclient.GetRuns(context.TODO(), runListOpts.phaseFilter, nil, groups, nil, runListOpts.start, runListOpts.limit, false) if err != nil { - return err + return errors.WithStack(err) } runs := make([]*runDetails, len(runsResp)) for i, runResponse := range runsResp { run, _, err := gwclient.GetRun(context.TODO(), runResponse.ID) if err != nil { - return err + return errors.WithStack(err) } tasks := []*taskDetails{} diff --git a/cmd/agola/cmd/serve.go b/cmd/agola/cmd/serve.go index eea6fcd..0557193 100644 --- a/cmd/agola/cmd/serve.go +++ b/cmd/agola/cmd/serve.go @@ -19,6 +19,7 @@ import ( "fmt" "agola.io/agola/cmd" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/config" "agola.io/agola/internal/services/configstore" "agola.io/agola/internal/services/executor" @@ -33,7 +34,6 @@ import ( "github.com/rs/zerolog/log" "github.com/spf13/cobra" "go.etcd.io/etcd/embed" - errors "golang.org/x/xerrors" ) var ( @@ -96,7 +96,7 @@ func embeddedEtcd(ctx context.Context) error { log.Info().Msgf("starting embedded etcd server") e, err := embed.StartEtcd(cfg) if err != nil { - return err + return errors.WithStack(err) } go func() { @@ -132,12 +132,12 @@ func serve(cmd *cobra.Command, args []string) error { c, err := config.Parse(serveOpts.config, serveOpts.components) if err != nil { - return errors.Errorf("config error: %w", err) + return errors.Wrapf(err, "config error") } if serveOpts.embeddedEtcd { if err := embeddedEtcd(ctx); err != nil { - return errors.Errorf("failed to start run service scheduler: %w", err) + return errors.Wrapf(err, "failed to start run service scheduler") } } @@ -145,7 +145,7 @@ func serve(cmd *cobra.Command, args []string) error { if isComponentEnabled("runservice") { rs, err = rsscheduler.NewRunservice(ctx, log.Logger, &c.Runservice) if err != nil { - return errors.Errorf("failed to start run service scheduler: %w", err) + return errors.Wrapf(err, "failed to start run service scheduler") } } @@ -153,7 +153,7 @@ func serve(cmd *cobra.Command, args []string) error { if isComponentEnabled("executor") { ex, err = executor.NewExecutor(ctx, log.Logger, &c.Executor) if err != nil { - return errors.Errorf("failed to start run service executor: %w", err) + return errors.Wrapf(err, "failed to start run service executor") } } @@ -161,7 +161,7 @@ func serve(cmd *cobra.Command, args []string) error { if isComponentEnabled("configstore") { cs, err = configstore.NewConfigstore(ctx, log.Logger, &c.Configstore) if err != nil { - return errors.Errorf("failed to start config store: %w", err) + return errors.Wrapf(err, "failed to start config store") } } @@ -169,7 +169,7 @@ func serve(cmd *cobra.Command, args []string) error { if isComponentEnabled("scheduler") { sched, err = scheduler.NewScheduler(ctx, log.Logger, &c.Scheduler) if err != nil { - return errors.Errorf("failed to start scheduler: %w", err) + return errors.Wrapf(err, "failed to start scheduler") } } @@ -177,7 +177,7 @@ func serve(cmd *cobra.Command, args []string) error { if isComponentEnabled("notification") { ns, err = notification.NewNotificationService(ctx, log.Logger, c) if err != nil { - return errors.Errorf("failed to start notification service: %w", err) + return errors.Wrapf(err, "failed to start notification service") } } @@ -185,7 +185,7 @@ func serve(cmd *cobra.Command, args []string) error { if isComponentEnabled("gateway") { gw, err = gateway.NewGateway(ctx, log.Logger, c) if err != nil { - return errors.Errorf("failed to start gateway: %w", err) + return errors.Wrapf(err, "failed to start gateway") } } @@ -193,7 +193,7 @@ func serve(cmd *cobra.Command, args []string) error { if isComponentEnabled("gitserver") { gs, err = gitserver.NewGitserver(ctx, log.Logger, &c.Gitserver) if err != nil { - return errors.Errorf("failed to start git server: %w", err) + return errors.Wrapf(err, "failed to start git server") } } diff --git a/cmd/agola/cmd/usercreate.go b/cmd/agola/cmd/usercreate.go index c7ddd0e..784deb5 100644 --- a/cmd/agola/cmd/usercreate.go +++ b/cmd/agola/cmd/usercreate.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdUserCreate = &cobra.Command{ @@ -63,7 +63,7 @@ func userCreate(cmd *cobra.Command, args []string) error { log.Info().Msgf("creating user") user, _, err := gwclient.CreateUser(context.TODO(), req) if err != nil { - return errors.Errorf("failed to create user: %w", err) + return errors.Wrapf(err, "failed to create user") } log.Info().Msgf("user %q created, ID: %q", user.UserName, user.ID) diff --git a/cmd/agola/cmd/userdelete.go b/cmd/agola/cmd/userdelete.go index 7ae959c..6acdce1 100644 --- a/cmd/agola/cmd/userdelete.go +++ b/cmd/agola/cmd/userdelete.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdUserDelete = &cobra.Command{ @@ -57,7 +57,7 @@ func userDelete(cmd *cobra.Command, args []string) error { log.Info().Msgf("deleting user %q", userDeleteOpts.username) if _, err := gwclient.DeleteUser(context.TODO(), userDeleteOpts.username); err != nil { - return errors.Errorf("failed to delete user: %w", err) + return errors.Wrapf(err, "failed to delete user") } return nil diff --git a/cmd/agola/cmd/userlacreate.go b/cmd/agola/cmd/userlacreate.go index 4661e6c..a026206 100644 --- a/cmd/agola/cmd/userlacreate.go +++ b/cmd/agola/cmd/userlacreate.go @@ -17,12 +17,12 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdUserLACreate = &cobra.Command{ @@ -74,7 +74,7 @@ func userLACreate(cmd *cobra.Command, args []string) error { log.Info().Msgf("creating linked account for user %q", userLACreateOpts.username) resp, _, err := gwclient.CreateUserLA(context.TODO(), userLACreateOpts.username, req) if err != nil { - return errors.Errorf("failed to create linked account: %w", err) + return errors.Wrapf(err, "failed to create linked account") } if resp.Oauth2Redirect != "" { log.Info().Msgf("visit %s to continue", resp.Oauth2Redirect) diff --git a/cmd/agola/cmd/userladelete.go b/cmd/agola/cmd/userladelete.go index 03109b3..671e726 100644 --- a/cmd/agola/cmd/userladelete.go +++ b/cmd/agola/cmd/userladelete.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdUserLADelete = &cobra.Command{ @@ -66,7 +66,7 @@ func userLADelete(cmd *cobra.Command, args []string) error { log.Info().Msgf("deleting linked account %q for user %q", laID, userName) _, err := gwclient.DeleteUserLA(context.TODO(), userName, laID) if err != nil { - return errors.Errorf("failed to delete linked account: %w", err) + return errors.Wrapf(err, "failed to delete linked account") } log.Info().Msgf("linked account %q for user %q deleted", laID, userName) diff --git a/cmd/agola/cmd/userlist.go b/cmd/agola/cmd/userlist.go index 193705f..fc48032 100644 --- a/cmd/agola/cmd/userlist.go +++ b/cmd/agola/cmd/userlist.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" @@ -62,7 +63,7 @@ func userList(cmd *cobra.Command, args []string) error { users, _, err := gwclient.GetUsers(context.TODO(), userListOpts.start, userListOpts.limit, false) if err != nil { - return err + return errors.WithStack(err) } printUsers(users) diff --git a/cmd/agola/cmd/usertokencreate.go b/cmd/agola/cmd/usertokencreate.go index 79711c3..b4b417d 100644 --- a/cmd/agola/cmd/usertokencreate.go +++ b/cmd/agola/cmd/usertokencreate.go @@ -18,12 +18,12 @@ import ( "context" "fmt" + "agola.io/agola/internal/errors" gwapitypes "agola.io/agola/services/gateway/api/types" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdUserTokenCreate = &cobra.Command{ @@ -69,7 +69,7 @@ func userTokenCreate(cmd *cobra.Command, args []string) error { log.Info().Msgf("creating token for user %q", userTokenCreateOpts.username) resp, _, err := gwclient.CreateUserToken(context.TODO(), userTokenCreateOpts.username, req) if err != nil { - return errors.Errorf("failed to create token: %w", err) + return errors.Wrapf(err, "failed to create token") } log.Info().Msgf("token for user %q created: %s", userTokenCreateOpts.username, resp.Token) fmt.Println(resp.Token) diff --git a/cmd/agola/cmd/usertokendelete.go b/cmd/agola/cmd/usertokendelete.go index 34149fb..a5417e2 100644 --- a/cmd/agola/cmd/usertokendelete.go +++ b/cmd/agola/cmd/usertokendelete.go @@ -17,11 +17,11 @@ package cmd import ( "context" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - errors "golang.org/x/xerrors" ) var cmdUserTokenDelete = &cobra.Command{ @@ -66,7 +66,7 @@ func userTokenDelete(cmd *cobra.Command, args []string) error { log.Info().Msgf("deleting token %q for user %q", tokenName, userName) _, err := gwclient.DeleteUserToken(context.TODO(), userName, tokenName) if err != nil { - return errors.Errorf("failed to delete user token: %w", err) + return errors.Wrapf(err, "failed to delete user token") } log.Info().Msgf("token %q for user %q deleted", tokenName, userName) diff --git a/cmd/agola/cmd/version.go b/cmd/agola/cmd/version.go index 7d396c7..cfd53ac 100644 --- a/cmd/agola/cmd/version.go +++ b/cmd/agola/cmd/version.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "agola.io/agola/internal/errors" gwclient "agola.io/agola/services/gateway/client" "github.com/rs/zerolog/log" @@ -43,7 +44,7 @@ func printVersions(cmd *cobra.Command, args []string) error { gwversion, _, err := gwclient.GetVersion(context.TODO()) if err != nil { - return err + return errors.WithStack(err) } fmt.Printf("Gateway version:\t%s\n", gwversion.Version) diff --git a/cmd/toolbox/cmd/createfile.go b/cmd/toolbox/cmd/createfile.go index 66d476f..e772737 100644 --- a/cmd/toolbox/cmd/createfile.go +++ b/cmd/toolbox/cmd/createfile.go @@ -21,6 +21,7 @@ import ( "log" "os" + "agola.io/agola/internal/errors" "github.com/spf13/cobra" ) @@ -48,18 +49,18 @@ func createFile(r io.Reader) (string, error) { // create a temp dir if the image doesn't have one tmpDir := os.TempDir() if err := os.MkdirAll(tmpDir, 0777); err != nil { - return "", fmt.Errorf("failed to create tmp dir %q", tmpDir) + return "", errors.Errorf("failed to create tmp dir %q", tmpDir) } file, err := ioutil.TempFile("", "") if err != nil { - return "", err + return "", errors.WithStack(err) } filename := file.Name() if _, err := io.Copy(file, r); err != nil { file.Close() - return "", err + return "", errors.WithStack(err) } file.Close() diff --git a/cmd/toolbox/cmd/template.go b/cmd/toolbox/cmd/template.go index 5708130..93c53e6 100644 --- a/cmd/toolbox/cmd/template.go +++ b/cmd/toolbox/cmd/template.go @@ -17,7 +17,6 @@ package cmd import ( "crypto/md5" "crypto/sha256" - "errors" "fmt" "io" "io/ioutil" @@ -28,6 +27,8 @@ import ( "text/template" "time" + "agola.io/agola/internal/errors" + "github.com/spf13/cobra" ) @@ -48,20 +49,20 @@ func md5sum(filename string) (string, error) { if info, err := os.Stat(filename); err == nil { if info.Size() > 1024*1024 { - return "", fmt.Errorf("file %q is too big", filename) + return "", errors.Errorf("file %q is too big", filename) } } else { - return "", err + return "", errors.WithStack(err) } f, err := os.Open(filename) if err != nil { - return "", err + return "", errors.WithStack(err) } h := md5.New() if _, err := io.Copy(h, f); err != nil { - return "", err + return "", errors.WithStack(err) } return fmt.Sprintf("%x", h.Sum(nil)), nil @@ -74,20 +75,20 @@ func sha256sum(filename string) (string, error) { if info, err := os.Stat(filename); err == nil { if info.Size() > 1024*1024 { - return "", fmt.Errorf("file %q is too big", filename) + return "", errors.Errorf("file %q is too big", filename) } } else { - return "", err + return "", errors.WithStack(err) } f, err := os.Open(filename) if err != nil { - return "", err + return "", errors.WithStack(err) } h := sha256.New() if _, err := io.Copy(h, f); err != nil { - return "", err + return "", errors.WithStack(err) } return fmt.Sprintf("%x", h.Sum(nil)), nil diff --git a/doc/devel.md b/doc/devel.md index 071aa09..a79c980 100644 --- a/doc/devel.md +++ b/doc/devel.md @@ -2,7 +2,7 @@ #### Start the web interface -* Clone the [agola-web repository](https://github.com/agola-io/agola-web) +- Clone the [agola-web repository](https://github.com/agola-io/agola-web) For the first time you'll need the `vue cli` and its services installed as global modules: @@ -27,7 +27,7 @@ make ### Start the agola server -* Copy the `example/config.yml` where you prefer +- Copy the `example/config.yml` where you prefer ``` ./bin/agola serve --embedded-etcd --config /path/to/your/config.yml --components all-base,executor @@ -38,3 +38,9 @@ or use an external etcd (set it in the config.yml): ``` ./bin/agola serve --config /path/to/your/config.yml --components all-base,executor ``` + +### Error handling + +Use the `--detailed-errors` option to easily follow the errors chain. + +When developing you should wrap every error using `errors.Wrap[f]` or `errors.WithStack`. The ci uses `golangci-lint` with the `wrapcheck` linter enabled to check if some errors aren't wrapped. diff --git a/go.mod b/go.mod index d8a0a92..3a56a1c 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,6 @@ require ( go.starlark.net v0.0.0-20200203144150-6677ee5c7211 golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 gopkg.in/src-d/go-billy.v4 v4.3.2 gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/yaml.v2 v2.2.8 diff --git a/internal/common/common.go b/internal/common/common.go index 1a64807..ac66850 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -21,12 +21,12 @@ import ( "os" "path" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/services/config" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) const ( @@ -43,7 +43,7 @@ func WriteFileAtomicFunc(filename string, perm os.FileMode, writeFunc func(f io. dir, name := path.Split(filename) f, err := ioutil.TempFile(dir, name) if err != nil { - return err + return errors.WithStack(err) } err = writeFunc(f) if err == nil { @@ -62,7 +62,7 @@ func WriteFileAtomicFunc(filename string, perm os.FileMode, writeFunc func(f io. if err != nil { os.Remove(f.Name()) } - return err + return errors.WithStack(err) } // WriteFileAtomic atomically writes a file @@ -70,7 +70,7 @@ func WriteFileAtomic(filename string, data []byte, perm os.FileMode) error { return WriteFileAtomicFunc(filename, perm, func(f io.Writer) error { _, err := f.Write(data) - return err + return errors.WithStack(err) }) } @@ -84,7 +84,7 @@ func NewObjectStorage(c *config.ObjectStorage) (*objectstorage.ObjStorage, error case config.ObjectStorageTypePosix: ost, err = objectstorage.NewPosix(c.Path) if err != nil { - return nil, errors.Errorf("failed to create posix object storage: %w", err) + return nil, errors.Wrapf(err, "failed to create posix object storage") } case config.ObjectStorageTypeS3: // minio golang client doesn't accept an url as an endpoint @@ -103,7 +103,7 @@ func NewObjectStorage(c *config.ObjectStorage) (*objectstorage.ObjStorage, error } ost, err = objectstorage.NewS3(c.Bucket, c.Location, endpoint, c.AccessKey, c.SecretAccessKey, secure) if err != nil { - return nil, errors.Errorf("failed to create s3 object storage: %w", err) + return nil, errors.Wrapf(err, "failed to create s3 object storage") } } @@ -121,7 +121,7 @@ func NewEtcd(c *config.Etcd, log zerolog.Logger, prefix string) (*etcd.Store, er SkipTLSVerify: c.TLSSkipVerify, }) if err != nil { - return nil, errors.Errorf("failed to create etcd store: %w", err) + return nil, errors.Wrapf(err, "failed to create etcd store") } return e, nil diff --git a/internal/config/config.go b/internal/config/config.go index f4b09aa..335ecdc 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -20,12 +20,12 @@ import ( "regexp" "strings" + "agola.io/agola/internal/errors" itypes "agola.io/agola/internal/services/types" "agola.io/agola/internal/util" "agola.io/agola/services/types" "github.com/ghodss/yaml" - errors "golang.org/x/xerrors" "k8s.io/apimachinery/pkg/api/resource" ) @@ -201,7 +201,7 @@ type SaveContent struct { func (s *Steps) UnmarshalJSON(b []byte) error { var stepsRaw []json.RawMessage if err := json.Unmarshal(b, &stepsRaw); err != nil { - return err + return errors.WithStack(err) } steps := make(Steps, len(stepsRaw)) @@ -210,13 +210,13 @@ func (s *Steps) UnmarshalJSON(b []byte) error { var stepMap map[string]json.RawMessage if err := json.Unmarshal(stepRaw, &stepMap); err != nil { - return err + return errors.WithStack(err) } // handle default step definition using format { type: "steptype", other steps fields } if _, ok := stepMap["type"]; ok { var stepTypeI interface{} if err := json.Unmarshal(stepMap["type"], &stepTypeI); err != nil { - return err + return errors.WithStack(err) } stepType, ok := stepTypeI.(string) if !ok { @@ -227,7 +227,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "clone": var s CloneStep if err := json.Unmarshal(stepRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -235,7 +235,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "run": var s RunStep if err := json.Unmarshal(stepRaw, &s); err != nil { - return err + return errors.WithStack(err) } if s.Tty == nil { s.Tty = util.BoolP(true) @@ -246,7 +246,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "save_to_workspace": var s SaveToWorkspaceStep if err := json.Unmarshal(stepRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -254,7 +254,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "restore_workspace": var s RestoreWorkspaceStep if err := json.Unmarshal(stepRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -262,7 +262,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "save_cache": var s SaveCacheStep if err := json.Unmarshal(stepRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -270,7 +270,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "restore_cache": var s RestoreCacheStep if err := json.Unmarshal(stepRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -285,14 +285,14 @@ func (s *Steps) UnmarshalJSON(b []byte) error { for stepType, stepSpecRaw := range stepMap { var stepSpec interface{} if err := json.Unmarshal(stepSpecRaw, &stepSpec); err != nil { - return err + return errors.WithStack(err) } switch stepType { case "clone": var s CloneStep if err := json.Unmarshal(stepSpecRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -304,7 +304,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { s.Command = stepSpec default: if err := json.Unmarshal(stepSpecRaw, &s); err != nil { - return err + return errors.WithStack(err) } } s.Type = stepType @@ -313,7 +313,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "save_to_workspace": var s SaveToWorkspaceStep if err := json.Unmarshal(stepSpecRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -321,7 +321,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "restore_workspace": var s RestoreWorkspaceStep if err := json.Unmarshal(stepSpecRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -329,7 +329,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "save_cache": var s SaveCacheStep if err := json.Unmarshal(stepSpecRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -337,7 +337,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error { case "restore_cache": var s RestoreCacheStep if err := json.Unmarshal(stepSpecRaw, &s); err != nil { - return err + return errors.WithStack(err) } s.Type = stepType step = &s @@ -359,14 +359,14 @@ func (d *Depends) UnmarshalJSON(b []byte) error { var dependsRaw []json.RawMessage if err := json.Unmarshal(b, &dependsRaw); err != nil { - return err + return errors.WithStack(err) } depends := make([]*Depend, len(dependsRaw)) for i, dependRaw := range dependsRaw { var dependi interface{} if err := json.Unmarshal(dependRaw, &dependi); err != nil { - return err + return errors.WithStack(err) } var depend *Depend isSimpler := false @@ -391,7 +391,7 @@ func (d *Depends) UnmarshalJSON(b []byte) error { if !isSimpler { // handle default depends definition using format "task": "taskname", conditions: [ list of conditions ] if err := json.Unmarshal(dependRaw, &depend); err != nil { - return err + return errors.WithStack(err) } } else { // handle simpler (for yaml) depends definition using format "taskname": [ list of conditions ] @@ -401,7 +401,7 @@ func (d *Depends) UnmarshalJSON(b []byte) error { type deplist map[string][]DependCondition var dl deplist if err := json.Unmarshal(dependRaw, &dl); err != nil { - return err + return errors.WithStack(err) } if len(dl) != 1 { return errors.Errorf("unsupported depend entry format") @@ -440,7 +440,7 @@ type Value struct { func (val *Value) UnmarshalJSON(b []byte) error { var ival interface{} if err := json.Unmarshal(b, &ival); err != nil { - return err + return errors.WithStack(err) } switch valValue := ival.(type) { case string: @@ -479,7 +479,7 @@ func (w *When) ToWhen() *types.When { func (w *When) UnmarshalJSON(b []byte) error { var wi *when if err := json.Unmarshal(b, &wi); err != nil { - return err + return errors.WithStack(err) } var err error @@ -487,21 +487,21 @@ func (w *When) UnmarshalJSON(b []byte) error { if wi.Branch != nil { w.Branch, err = parseWhenConditions(wi.Branch) if err != nil { - return err + return errors.WithStack(err) } } if wi.Tag != nil { w.Tag, err = parseWhenConditions(wi.Tag) if err != nil { - return err + return errors.WithStack(err) } } if wi.Ref != nil { w.Ref, err = parseWhenConditions(wi.Ref) if err != nil { - return err + return errors.WithStack(err) } } @@ -521,7 +521,7 @@ func parseWhenConditions(wi interface{}) (*types.WhenConditions, error) { case []interface{}: ss, err := parseSliceString(c) if err != nil { - return nil, err + return nil, errors.WithStack(err) } include = ss case map[string]interface{}: @@ -530,12 +530,12 @@ func parseWhenConditions(wi interface{}) (*types.WhenConditions, error) { case "include": include, err = parseStringOrSlice(v) if err != nil { - return nil, err + return nil, errors.WithStack(err) } case "exclude": exclude, err = parseStringOrSlice(v) if err != nil { - return nil, err + return nil, errors.WithStack(err) } default: return nil, errors.Errorf(`expected one of "include" or "exclude", got %s`, k) @@ -547,11 +547,11 @@ func parseWhenConditions(wi interface{}) (*types.WhenConditions, error) { w.Include, err = parseWhenConditionSlice(include) if err != nil { - return nil, err + return nil, errors.WithStack(err) } w.Exclude, err = parseWhenConditionSlice(exclude) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return w, nil @@ -566,7 +566,7 @@ func parseWhenConditionSlice(conds []string) ([]types.WhenCondition, error) { for _, cond := range conds { wc, err := parseWhenCondition(cond) if err != nil { - return nil, err + return nil, errors.WithStack(err) } wcs = append(wcs, *wc) } @@ -590,7 +590,7 @@ func parseWhenCondition(s string) (*types.WhenCondition, error) { if isRegExp { if _, err := regexp.Compile(s); err != nil { - return nil, errors.Errorf("wrong regular expression: %w", err) + return nil, errors.Wrapf(err, "wrong regular expression") } wc.Type = types.WhenConditionTypeRegExp } else { @@ -608,7 +608,7 @@ func parseStringOrSlice(si interface{}) ([]string, error) { var err error ss, err = parseSliceString(c) if err != nil { - return nil, err + return nil, errors.WithStack(err) } } return ss, nil @@ -669,14 +669,14 @@ func ParseConfig(configData []byte, format ConfigFormat, configContext *ConfigCo var err error configData, err = execJsonnet(configData, configContext) if err != nil { - return nil, errors.Errorf("failed to execute jsonnet: %w", err) + return nil, errors.Wrapf(err, "failed to execute jsonnet") } case ConfigFormatStarlark: // Generate json from starlark var err error configData, err = execStarlark(configData, configContext) if err != nil { - return nil, errors.Errorf("failed to execute starlark: %w", err) + return nil, errors.Wrapf(err, "failed to execute starlark") } } @@ -686,7 +686,7 @@ func ParseConfig(configData []byte, format ConfigFormat, configContext *ConfigCo config := DefaultConfig if err := yaml.Unmarshal(configData, &config); err != nil { - return nil, errors.Errorf("failed to unmarshal config: %w", err) + return nil, errors.Wrapf(err, "failed to unmarshal config") } return &config, checkConfig(&config) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index d817396..c2c2023 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -15,14 +15,13 @@ package config import ( - "fmt" "testing" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" "agola.io/agola/services/types" "github.com/google/go-cmp/cmp" - errors "golang.org/x/xerrors" "k8s.io/apimachinery/pkg/api/resource" ) @@ -35,14 +34,14 @@ func TestParseConfig(t *testing.T) { { name: "test no runs 1", in: ``, - err: fmt.Errorf(`no runs defined`), + err: errors.Errorf(`no runs defined`), }, { name: "test no runs 2", in: ` runs: `, - err: fmt.Errorf(`no runs defined`), + err: errors.Errorf(`no runs defined`), }, { name: "test empty run", @@ -50,7 +49,7 @@ func TestParseConfig(t *testing.T) { runs: - `, - err: fmt.Errorf(`run at index 0 is empty`), + err: errors.Errorf(`run at index 0 is empty`), }, { name: "test empty task", @@ -60,7 +59,7 @@ func TestParseConfig(t *testing.T) { tasks: - `, - err: fmt.Errorf(`run "run01": task at index 0 is empty`), + err: errors.Errorf(`run "run01": task at index 0 is empty`), }, { name: "test empty runtime arch", @@ -88,7 +87,7 @@ func TestParseConfig(t *testing.T) { containers: - image: busybox `, - err: fmt.Errorf(`task "task01" runtime: invalid arch "invalidarch"`), + err: errors.Errorf(`task "task01" runtime: invalid arch "invalidarch"`), }, { name: "test missing task dependency", @@ -104,7 +103,7 @@ func TestParseConfig(t *testing.T) { depends: - task02 `, - err: fmt.Errorf(`run task "task02" needed by task "task01" doesn't exist`), + err: errors.Errorf(`run task "task02" needed by task "task01" doesn't exist`), }, { name: "test circular dependency between 2 tasks a -> b -> a", diff --git a/internal/config/jsonnet.go b/internal/config/jsonnet.go index 74d35f4..c79248c 100644 --- a/internal/config/jsonnet.go +++ b/internal/config/jsonnet.go @@ -17,21 +17,21 @@ package config import ( "encoding/json" + "agola.io/agola/internal/errors" "github.com/google/go-jsonnet" - errors "golang.org/x/xerrors" ) func execJsonnet(configData []byte, configContext *ConfigContext) ([]byte, error) { vm := jsonnet.MakeVM() cj, err := json.Marshal(configContext) if err != nil { - return nil, errors.Errorf("failed to marshal config context: %w", err) + return nil, errors.Wrapf(err, "failed to marshal config context") } vm.TLACode("ctx", string(cj)) out, err := vm.EvaluateSnippet("", string(configData)) if err != nil { - return nil, errors.Errorf("failed to evaluate jsonnet config: %w", err) + return nil, errors.Wrapf(err, "failed to evaluate jsonnet config") } return []byte(out), nil diff --git a/internal/config/starlark.go b/internal/config/starlark.go index 1329127..29ac7d4 100644 --- a/internal/config/starlark.go +++ b/internal/config/starlark.go @@ -19,29 +19,29 @@ import ( "encoding/json" "fmt" + "agola.io/agola/internal/errors" "go.starlark.net/starlark" - errors "golang.org/x/xerrors" ) func starlarkArgs(cc *ConfigContext) (starlark.Tuple, error) { d := &starlark.Dict{} if err := d.SetKey(starlark.String("ref_type"), starlark.String(cc.RefType)); err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := d.SetKey(starlark.String("ref"), starlark.String(cc.Ref)); err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := d.SetKey(starlark.String("branch"), starlark.String(cc.Branch)); err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := d.SetKey(starlark.String("tag"), starlark.String(cc.Tag)); err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := d.SetKey(starlark.String("pull_request_id"), starlark.String(cc.PullRequestID)); err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := d.SetKey(starlark.String("commit_sha"), starlark.String(cc.CommitSHA)); err != nil { - return nil, err + return nil, errors.WithStack(err) } return []starlark.Value{d}, nil @@ -59,13 +59,13 @@ func starlarkJSON(out *bytes.Buffer, v starlark.Value) error { case starlark.Int: data, err := json.Marshal(v.BigInt()) if err != nil { - return err + return errors.WithStack(err) } out.Write(data) case starlark.Float: data, err := json.Marshal(float64(v)) if err != nil { - return err + return errors.WithStack(err) } out.Write(data) case starlark.String: @@ -76,7 +76,7 @@ func starlarkJSON(out *bytes.Buffer, v starlark.Value) error { e := json.NewEncoder(data) e.SetEscapeHTML(false) if err := e.Encode(string(v)); err != nil { - return err + return errors.WithStack(err) } // remove final \n introduced by the encoder out.Write(bytes.TrimSuffix(data.Bytes(), []byte("\n"))) @@ -87,7 +87,7 @@ func starlarkJSON(out *bytes.Buffer, v starlark.Value) error { out.WriteString(", ") } if err := starlarkJSON(out, v.Index(i)); err != nil { - return err + return errors.WithStack(err) } } out.WriteByte(']') @@ -98,20 +98,20 @@ func starlarkJSON(out *bytes.Buffer, v starlark.Value) error { out.WriteString(", ") } if _, ok := item[0].(starlark.String); !ok { - return fmt.Errorf("cannot convert non-string dict key to JSON") + return errors.Errorf("cannot convert non-string dict key to JSON") } if err := starlarkJSON(out, item[0]); err != nil { - return err + return errors.WithStack(err) } out.WriteString(": ") if err := starlarkJSON(out, item[1]); err != nil { - return err + return errors.WithStack(err) } } out.WriteByte('}') default: - return fmt.Errorf("cannot convert starlark type %q to JSON", v.Type()) + return errors.Errorf("cannot convert starlark type %q to JSON", v.Type()) } return nil } @@ -124,7 +124,7 @@ func execStarlark(configData []byte, configContext *ConfigContext) ([]byte, erro } globals, err := starlark.ExecFile(thread, "config.star", configData, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // we require a main function that will be called wiht one @@ -139,18 +139,18 @@ func execStarlark(configData []byte, configContext *ConfigContext) ([]byte, erro } args, err := starlarkArgs(configContext) if err != nil { - return nil, errors.Errorf("cannot create startlark arguments: %w", err) + return nil, errors.Wrapf(err, "cannot create startlark arguments") } mainVal, err = starlark.Call(thread, main, args, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } buf := new(bytes.Buffer) switch v := mainVal.(type) { case *starlark.Dict: if err := starlarkJSON(buf, v); err != nil { - return nil, err + return nil, errors.WithStack(err) } default: return nil, errors.Errorf("wrong starlark output, must be a dict") diff --git a/internal/config/starlark_test.go b/internal/config/starlark_test.go index d9e6b14..830f1e5 100644 --- a/internal/config/starlark_test.go +++ b/internal/config/starlark_test.go @@ -16,10 +16,10 @@ package config import ( "bytes" - "fmt" "math" "testing" + "agola.io/agola/internal/errors" "github.com/google/go-cmp/cmp" "go.starlark.net/starlark" ) @@ -48,7 +48,7 @@ func TestStarlarkJSON(t *testing.T) { _ = s.SetKey(starlark.MakeInt(10), starlark.String("string01")) return starlark.Value(s) }(), - err: fmt.Errorf("cannot convert non-string dict key to JSON"), + err: errors.Errorf("cannot convert non-string dict key to JSON"), }, { name: "test list", diff --git a/internal/datamanager/changes.go b/internal/datamanager/changes.go index 1e9a1c2..6fb78b0 100644 --- a/internal/datamanager/changes.go +++ b/internal/datamanager/changes.go @@ -24,11 +24,11 @@ import ( "sync" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" etcdclientv3rpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" "go.etcd.io/etcd/mvcc/mvccpb" - errors "golang.org/x/xerrors" ) // TODO(sgotti) rewrite this to use a sqlite local cache @@ -132,7 +132,7 @@ func (d *DataManager) applyWalChanges(ctx context.Context, walData *WalData, rev walDataFile, err := d.ost.ReadObject(walDataFilePath) if err != nil { - return errors.Errorf("failed to read waldata %q: %w", walDataFilePath, err) + return errors.Wrapf(err, "failed to read waldata %q", walDataFilePath) } defer walDataFile.Close() dec := json.NewDecoder(walDataFile) @@ -148,7 +148,7 @@ func (d *DataManager) applyWalChanges(ctx context.Context, walData *WalData, rev break } if err != nil { - return errors.Errorf("failed to decode wal file: %w", err) + return errors.Wrapf(err, "failed to decode wal file") } d.applyWalChangesAction(ctx, action, walData.WalSequence, revision) @@ -200,7 +200,7 @@ func (d *DataManager) initializeChanges(ctx context.Context) error { for { listResp, err := d.e.ListPaged(ctx, etcdWalsDir+"/", 0, 10, continuation) if err != nil { - return err + return errors.WithStack(err) } resp := listResp.Resp continuation = listResp.Continuation @@ -210,10 +210,10 @@ func (d *DataManager) initializeChanges(ctx context.Context) error { for _, kv := range resp.Kvs { var walData *WalData if err := json.Unmarshal(kv.Value, &walData); err != nil { - return err + return errors.WithStack(err) } if err := d.applyWalChanges(ctx, walData, revision); err != nil { - return err + return errors.WithStack(err) } } if !listResp.HasMore { @@ -226,7 +226,7 @@ func (d *DataManager) initializeChanges(ctx context.Context) error { for { listResp, err := d.e.ListPaged(ctx, etcdChangeGroupsDir+"/", 0, 10, continuation) if err != nil { - return err + return errors.WithStack(err) } resp := listResp.Resp continuation = listResp.Continuation @@ -267,7 +267,7 @@ func (d *DataManager) watcher(ctx context.Context) error { d.changes.initialized = false d.changes.Unlock() } - return errors.Errorf("watch error: %w", err) + return errors.Wrapf(err, "watch error") } revision := wresp.Header.Revision @@ -280,13 +280,13 @@ func (d *DataManager) watcher(ctx context.Context) error { case mvccpb.PUT: var walData *WalData if err := json.Unmarshal(ev.Kv.Value, &walData); err != nil { - return err + return errors.WithStack(err) } if walData.WalStatus != WalStatusCommitted { continue } if err := d.applyWalChanges(ctx, walData, revision); err != nil { - return err + return errors.WithStack(err) } case mvccpb.DELETE: walseq := path.Base(string(key)) diff --git a/internal/datamanager/data.go b/internal/datamanager/data.go index 76887fe..0f3dfce 100644 --- a/internal/datamanager/data.go +++ b/internal/datamanager/data.go @@ -26,11 +26,11 @@ import ( "sort" "strings" + "agola.io/agola/internal/errors" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/sequence" "github.com/gofrs/uuid" - errors "golang.org/x/xerrors" ) // ErrNoDataStatus represent when there's no data status files in the ost @@ -96,12 +96,12 @@ func (d *DataManager) walIndex(ctx context.Context, wals []*WalData) (walIndex, for _, walData := range wals { header, err := d.ReadWal(walData.WalSequence) if err != nil { - return nil, err + return nil, errors.WithStack(err) } walFile, err := d.ReadWalData(header.WalDataFileID) if err != nil { - return nil, errors.Errorf("cannot read wal data file %q: %w", header.WalDataFileID, err) + return nil, errors.Wrapf(err, "cannot read wal data file %q", header.WalDataFileID) } defer walFile.Close() @@ -115,7 +115,7 @@ func (d *DataManager) walIndex(ctx context.Context, wals []*WalData) (walIndex, break } if err != nil { - return nil, errors.Errorf("failed to decode wal file: %w", err) + return nil, errors.Wrapf(err, "failed to decode wal file") } if _, ok := wimap[action.DataType]; !ok { @@ -148,7 +148,7 @@ func (d *DataManager) walIndex(ctx context.Context, wals []*WalData) (walIndex, func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) error { dataSequence, err := sequence.IncSequence(ctx, d.e, etcdCheckpointSeqKey) if err != nil { - return err + return errors.WithStack(err) } var lastWalSequence string @@ -164,7 +164,7 @@ func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) er curDataStatus, err := d.GetLastDataStatus() if err != nil && !errors.Is(err, ErrNoDataStatus) { - return err + return errors.WithStack(err) } startWalIndex := 0 @@ -184,7 +184,7 @@ func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) er wi, err := d.walIndex(ctx, wals) if err != nil { - return err + return errors.WithStack(err) } for _, dataType := range d.dataTypes { @@ -194,14 +194,14 @@ func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) er } dataStatusFiles, err := d.writeDataType(ctx, wi, dataType, dataSequence, curDataStatusFiles) if err != nil { - return err + return errors.WithStack(err) } dataStatus.Files[dataType] = dataStatusFiles } dataStatusj, err := json.Marshal(dataStatus) if err != nil { - return err + return errors.WithStack(err) } if err := d.ost.WriteObject(d.dataStatusPath(dataSequence), bytes.NewReader(dataStatusj), int64(len(dataStatusj)), true); err != nil { return fromOSTError(err) @@ -212,7 +212,7 @@ func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) er func (d *DataManager) writeDataFile(ctx context.Context, buf *bytes.Buffer, size int64, dataFileIndex *DataFileIndex, dataFileID, dataType string) error { if buf.Len() == 0 { - return fmt.Errorf("empty data entries") + return errors.Errorf("empty data entries") } if err := d.ost.WriteObject(d.DataFilePath(dataType, dataFileID), buf, size, true); err != nil { @@ -221,7 +221,7 @@ func (d *DataManager) writeDataFile(ctx context.Context, buf *bytes.Buffer, size dataFileIndexj, err := json.Marshal(dataFileIndex) if err != nil { - return err + return errors.WithStack(err) } if err := d.ost.WriteObject(d.DataFileIndexPath(dataType, dataFileID), bytes.NewReader(dataFileIndexj), int64(len(dataFileIndexj)), true); err != nil { return fromOSTError(err) @@ -354,7 +354,7 @@ func (d *DataManager) writeDataType(ctx context.Context, wi walIndex, dataType s } if err != nil { oldDataf.Close() - return nil, err + return nil, errors.WithStack(err) } dataEntries = append(dataEntries, de) @@ -434,10 +434,10 @@ func (d *DataManager) writeDataType(ctx context.Context, wi walIndex, dataType s lastEntryID = de.ID dataEntryj, err := json.Marshal(de) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if _, err := buf.Write(dataEntryj); err != nil { - return nil, err + return nil, errors.WithStack(err) } dataFileIndex.Index[de.ID] = pos - lastSplitPos prevPos := pos @@ -470,7 +470,7 @@ func (d *DataManager) writeDataType(ctx context.Context, wi walIndex, dataType s for i, sp := range splitPoints { curDataFileID := d.dataFileID(dataSequence, uuid.Must(uuid.NewV4()).String()) if err := d.writeDataFile(ctx, &buf, sp.pos-curPos, dataFileIndexes[i], curDataFileID, dataType); err != nil { - return nil, err + return nil, errors.WithStack(err) } // insert new dataStatusFile dataStatusFiles = append(dataStatusFiles, &DataStatusFile{ @@ -492,7 +492,7 @@ func (d *DataManager) writeDataType(ctx context.Context, wi walIndex, dataType s func (d *DataManager) Read(dataType, id string) (io.Reader, error) { curDataStatus, err := d.GetLastDataStatus() if err != nil { - return nil, err + return nil, errors.WithStack(err) } curFiles := curDataStatus.Files @@ -519,7 +519,7 @@ func (d *DataManager) Read(dataType, id string) (io.Reader, error) { err = dec.Decode(&dataFileIndex) if err != nil { dataFileIndexf.Close() - return nil, err + return nil, errors.WithStack(err) } dataFileIndexf.Close() @@ -534,13 +534,13 @@ func (d *DataManager) Read(dataType, id string) (io.Reader, error) { } if _, err := dataf.Seek(int64(pos), io.SeekStart); err != nil { dataf.Close() - return nil, err + return nil, errors.WithStack(err) } var de *DataEntry dec = json.NewDecoder(dataf) if err := dec.Decode(&de); err != nil { dataf.Close() - return nil, err + return nil, errors.WithStack(err) } dataf.Close() @@ -640,7 +640,7 @@ func (d *DataManager) GetDataStatus(dataSequence *sequence.Sequence) (*DataStatu func (d *DataManager) GetFirstDataStatusSequence() (*sequence.Sequence, error) { dataStatusSequences, err := d.GetFirstDataStatusSequences(1) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return dataStatusSequences[0], nil @@ -649,7 +649,7 @@ func (d *DataManager) GetFirstDataStatusSequence() (*sequence.Sequence, error) { func (d *DataManager) GetLastDataStatusSequence() (*sequence.Sequence, error) { dataStatusSequences, err := d.GetLastDataStatusSequences(1) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return dataStatusSequences[0], nil @@ -658,7 +658,7 @@ func (d *DataManager) GetLastDataStatusSequence() (*sequence.Sequence, error) { func (d *DataManager) GetFirstDataStatus() (*DataStatus, error) { dataStatusSequence, err := d.GetFirstDataStatusSequence() if err != nil { - return nil, err + return nil, errors.WithStack(err) } return d.GetDataStatus(dataStatusSequence) @@ -667,7 +667,7 @@ func (d *DataManager) GetFirstDataStatus() (*DataStatus, error) { func (d *DataManager) GetLastDataStatus() (*DataStatus, error) { dataStatusSequence, err := d.GetLastDataStatusSequence() if err != nil { - return nil, err + return nil, errors.WithStack(err) } return d.GetDataStatus(dataStatusSequence) @@ -675,12 +675,12 @@ func (d *DataManager) GetLastDataStatus() (*DataStatus, error) { func (d *DataManager) Export(ctx context.Context, w io.Writer) error { if err := d.checkpoint(ctx, true); err != nil { - return err + return errors.WithStack(err) } curDataStatus, err := d.GetLastDataStatus() if err != nil { - return err + return errors.WithStack(err) } for _, dataType := range d.dataTypes { @@ -695,7 +695,7 @@ func (d *DataManager) Export(ctx context.Context, w io.Writer) error { } if _, err := io.Copy(w, dataf); err != nil { dataf.Close() - return err + return errors.WithStack(err) } dataf.Close() @@ -708,7 +708,7 @@ func (d *DataManager) Export(ctx context.Context, w io.Writer) error { func (d *DataManager) Import(ctx context.Context, r io.Reader) error { // delete contents in etcd if err := d.deleteEtcd(ctx); err != nil { - return err + return errors.WithStack(err) } // we require all entries of the same datatypes grouped together @@ -717,7 +717,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error { // create a new sequence, we assume that it'll be greater than previous data sequences dataSequence, err := sequence.IncSequence(ctx, d.e, etcdCheckpointSeqKey) if err != nil { - return err + return errors.WithStack(err) } dataStatus := &DataStatus{ @@ -745,7 +745,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error { if errors.Is(err, io.EOF) { dataFileID := d.dataFileID(dataSequence, uuid.Must(uuid.NewV4()).String()) if err := d.writeDataFile(ctx, &buf, int64(buf.Len()), dataFileIndex, dataFileID, curDataType); err != nil { - return err + return errors.WithStack(err) } dataStatusFiles = append(dataStatusFiles, &DataStatusFile{ @@ -779,7 +779,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error { if mustWrite { dataFileID := d.dataFileID(dataSequence, uuid.Must(uuid.NewV4()).String()) if err := d.writeDataFile(ctx, &buf, int64(buf.Len()), dataFileIndex, dataFileID, curDataType); err != nil { - return err + return errors.WithStack(err) } dataStatusFiles = append(dataStatusFiles, &DataStatusFile{ @@ -810,10 +810,10 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error { dataEntryj, err := json.Marshal(de) if err != nil { - return err + return errors.WithStack(err) } if _, err := buf.Write(dataEntryj); err != nil { - return err + return errors.WithStack(err) } dataFileIndex.Index[de.ID] = pos pos += int64(len(dataEntryj)) @@ -821,7 +821,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error { dataStatusj, err := json.Marshal(dataStatus) if err != nil { - return err + return errors.WithStack(err) } if err := d.ost.WriteObject(d.dataStatusPath(dataSequence), bytes.NewReader(dataStatusj), int64(len(dataStatusj)), true); err != nil { return fromOSTError(err) @@ -829,7 +829,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error { // initialize etcd providing the specific datastatus if err := d.InitEtcd(ctx, dataStatus); err != nil { - return err + return errors.WithStack(err) } return nil @@ -838,7 +838,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error { func (d *DataManager) CleanOldCheckpoints(ctx context.Context) error { dataStatusSequences, err := d.GetLastDataStatusSequences(dataStatusToKeep) if err != nil { - return err + return errors.WithStack(err) } return d.cleanOldCheckpoints(ctx, dataStatusSequences) @@ -894,7 +894,7 @@ func (d *DataManager) cleanOldCheckpoints(ctx context.Context, dataStatusSequenc for _, dataStatusSequence := range dataStatusSequences { dataStatus, err := d.GetDataStatus(dataStatusSequence) if err != nil { - return err + return errors.WithStack(err) } for dataType := range dataStatus.Files { diff --git a/internal/datamanager/datamanager.go b/internal/datamanager/datamanager.go index f861c19..b11a32f 100644 --- a/internal/datamanager/datamanager.go +++ b/internal/datamanager/datamanager.go @@ -21,12 +21,12 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/sequence" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) // TODO(sgotti) handle etcd unwanted changes: @@ -252,7 +252,7 @@ func (d *DataManager) deleteEtcd(ctx context.Context) error { } for _, prefix := range prefixes { if err := d.e.DeletePrefix(ctx, prefix); err != nil { - return err + return errors.WithStack(err) } } diff --git a/internal/datamanager/datamanager_test.go b/internal/datamanager/datamanager_test.go index 6116b55..7af3579 100644 --- a/internal/datamanager/datamanager_test.go +++ b/internal/datamanager/datamanager_test.go @@ -29,12 +29,12 @@ import ( "testing" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/testutil" "github.com/google/go-cmp/cmp" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) func setupEtcd(t *testing.T, log zerolog.Logger, dir string) *testutil.TestEmbeddedEtcd { @@ -612,7 +612,7 @@ func doAndCheckCheckpoint(t *testing.T, ctx context.Context, dm *DataManager, ac // populate with a wal _, err := dm.WriteWal(ctx, actionGroup, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } } @@ -621,11 +621,11 @@ func doAndCheckCheckpoint(t *testing.T, ctx context.Context, dm *DataManager, ac // do a checkpoint if err := dm.checkpoint(ctx, true); err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := checkDataFiles(ctx, t, dm, expectedEntries); err != nil { - return nil, err + return nil, errors.WithStack(err) } return expectedEntries, nil @@ -635,7 +635,7 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected // read the data file curDataStatus, err := dm.GetLastDataStatus() if err != nil { - return err + return errors.WithStack(err) } allEntriesMap := map[string]*DataEntry{} @@ -645,14 +645,14 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected for i, file := range curDataStatus.Files[dataType] { dataFileIndexf, err := dm.ost.ReadObject(dm.DataFileIndexPath(dataType, file.ID)) if err != nil { - return err + return errors.WithStack(err) } var dataFileIndex *DataFileIndex dec := json.NewDecoder(dataFileIndexf) err = dec.Decode(&dataFileIndex) if err != nil { dataFileIndexf.Close() - return err + return errors.WithStack(err) } dataFileIndexf.Close() @@ -660,7 +660,7 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected dataEntries := []*DataEntry{} dataf, err := dm.ost.ReadObject(dm.DataFilePath(dataType, file.ID)) if err != nil { - return err + return errors.WithStack(err) } dec = json.NewDecoder(dataf) var prevEntryID string @@ -674,15 +674,15 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected } if err != nil { dataf.Close() - return err + return errors.WithStack(err) } // check that there are no duplicate entries if _, ok := allEntriesMap[de.ID]; ok { - return fmt.Errorf("duplicate entry id: %s", de.ID) + return errors.Errorf("duplicate entry id: %s", de.ID) } // check that the entries are in order if de.ID < prevEntryID { - return fmt.Errorf("previous entry id: %s greater than entry id: %s", prevEntryID, de.ID) + return errors.Errorf("previous entry id: %s greater than entry id: %s", prevEntryID, de.ID) } dataEntriesMap[de.ID] = de @@ -693,7 +693,7 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected // check that the index matches the entries if len(dataFileIndex.Index) != len(dataEntriesMap) { - return fmt.Errorf("index entries: %d different than data entries: %d", len(dataFileIndex.Index), len(dataEntriesMap)) + return errors.Errorf("index entries: %d different than data entries: %d", len(dataFileIndex.Index), len(dataEntriesMap)) } indexIDs := make([]string, len(dataFileIndex.Index)) entriesIDs := make([]string, len(dataEntriesMap)) @@ -706,19 +706,19 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected sort.Strings(indexIDs) sort.Strings(entriesIDs) if !reflect.DeepEqual(indexIDs, entriesIDs) { - return fmt.Errorf("index entries ids don't match data entries ids: index: %v, data: %v", indexIDs, entriesIDs) + return errors.Errorf("index entries ids don't match data entries ids: index: %v, data: %v", indexIDs, entriesIDs) } if file.LastEntryID != dataEntries[len(dataEntries)-1].ID { - return fmt.Errorf("lastEntryID for datafile %d: %s is different than real last entry id: %s", i, file.LastEntryID, dataEntries[len(dataEntries)-1].ID) + return errors.Errorf("lastEntryID for datafile %d: %s is different than real last entry id: %s", i, file.LastEntryID, dataEntries[len(dataEntries)-1].ID) } // check that all the files are in order if file.LastEntryID == prevLastEntryID { - return fmt.Errorf("lastEntryID for datafile %d is equal than previous file lastEntryID: %s == %s", i, file.LastEntryID, prevLastEntryID) + return errors.Errorf("lastEntryID for datafile %d is equal than previous file lastEntryID: %s == %s", i, file.LastEntryID, prevLastEntryID) } if file.LastEntryID < prevLastEntryID { - return fmt.Errorf("lastEntryID for datafile %d is less than previous file lastEntryID: %s < %s", i, file.LastEntryID, prevLastEntryID) + return errors.Errorf("lastEntryID for datafile %d is less than previous file lastEntryID: %s < %s", i, file.LastEntryID, prevLastEntryID) } prevLastEntryID = file.LastEntryID } @@ -726,10 +726,10 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected // check that the number of entries is right if len(allEntriesMap) != len(expectedEntriesMap) { - return fmt.Errorf("expected %d total entries, got %d", len(expectedEntriesMap), len(allEntriesMap)) + return errors.Errorf("expected %d total entries, got %d", len(expectedEntriesMap), len(allEntriesMap)) } if !reflect.DeepEqual(expectedEntriesMap, allEntriesMap) { - return fmt.Errorf("expected entries don't match current entries") + return errors.Errorf("expected entries don't match current entries") } return nil diff --git a/internal/datamanager/wal.go b/internal/datamanager/wal.go index acc87d8..63450cd 100644 --- a/internal/datamanager/wal.go +++ b/internal/datamanager/wal.go @@ -25,6 +25,7 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/sequence" @@ -34,7 +35,6 @@ import ( "go.etcd.io/etcd/clientv3/concurrency" etcdclientv3rpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" "go.etcd.io/etcd/mvcc/mvccpb" - errors "golang.org/x/xerrors" ) type ActionType string @@ -127,7 +127,7 @@ func (d *DataManager) ReadObject(dataType, id string, cgNames []string) (io.Read } f, err := d.Read(dataType, id) - return ioutil.NopCloser(f), cgt, err + return ioutil.NopCloser(f), cgt, errors.WithStack(err) } func (d *DataManager) HasOSTWal(walseq string) (bool, error) { @@ -150,7 +150,7 @@ func (d *DataManager) ReadWal(walseq string) (*WalHeader, error) { dec := json.NewDecoder(walFilef) var header *WalHeader if err = dec.Decode(&header); err != nil { - return nil, err + return nil, errors.WithStack(err) } return header, nil @@ -260,7 +260,7 @@ func (d *DataManager) ListEtcdChangeGroups(ctx context.Context, revision int64) changeGroupsRevisions := changeGroupsRevisions{} resp, err := d.e.List(ctx, etcdChangeGroupsDir, "", revision) if err != nil { - return nil, err + return nil, errors.WithStack(err) } for _, kv := range resp.Kvs { changegroupID := path.Base(string(kv.Key)) @@ -277,7 +277,7 @@ func (d *DataManager) FirstAvailableWalData(ctx context.Context) (*WalData, int6 // list waldata and just get the first if available listResp, err := d.e.ListPaged(ctx, etcdWalsDir, 0, 1, nil) if err != nil { - return nil, 0, err + return nil, 0, errors.WithStack(err) } resp := listResp.Resp revision := resp.Header.Revision @@ -288,7 +288,7 @@ func (d *DataManager) FirstAvailableWalData(ctx context.Context) (*WalData, int6 var walData *WalData if err := json.Unmarshal(resp.Kvs[0].Value, &walData); err != nil { - return nil, 0, err + return nil, 0, errors.WithStack(err) } return walData, revision, nil @@ -297,7 +297,7 @@ func (d *DataManager) FirstAvailableWalData(ctx context.Context) (*WalData, int6 func (d *DataManager) LastCommittedStorageWal(ctx context.Context) (string, int64, error) { resp, err := d.e.Get(ctx, etcdLastCommittedStorageWalSeqKey, 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return "", 0, err + return "", 0, errors.WithStack(err) } if errors.Is(err, etcd.ErrKeyNotFound) { return "", 0, errors.Errorf("no last committedstorage wal on etcd") @@ -424,17 +424,17 @@ func (d *DataManager) WriteWalAdditionalOps(ctx context.Context, actions []*Acti walSequence, err := sequence.IncSequence(ctx, d.e, etcdWalSeqKey) if err != nil { - return nil, err + return nil, errors.WithStack(err) } resp, err := d.e.Get(ctx, etcdWalsDataKey, 0) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var walsData WalsData if err := json.Unmarshal(resp.Kvs[0].Value, &walsData); err != nil { - return nil, err + return nil, errors.WithStack(err) } walsData.Revision = resp.Kvs[0].ModRevision @@ -446,10 +446,10 @@ func (d *DataManager) WriteWalAdditionalOps(ctx context.Context, actions []*Acti for _, action := range actions { actionj, err := json.Marshal(action) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if _, err := buf.Write(actionj); err != nil { - return nil, err + return nil, errors.WithStack(err) } } if err := d.ost.WriteObject(walDataFilePath, bytes.NewReader(buf.Bytes()), int64(buf.Len()), true); err != nil { @@ -468,11 +468,11 @@ func (d *DataManager) WriteWalAdditionalOps(ctx context.Context, actions []*Acti walsDataj, err := json.Marshal(walsData) if err != nil { - return nil, err + return nil, errors.WithStack(err) } walDataj, err := json.Marshal(walData) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if cmp == nil { @@ -512,7 +512,7 @@ func (d *DataManager) WriteWalAdditionalOps(ctx context.Context, actions []*Acti txn := d.e.Client().Txn(ctx).If(cmp...).Then(then...).Else(getWalsData, getWal) tresp, err := txn.Commit() if err != nil { - return nil, etcd.FromEtcdError(err) + return nil, errors.WithStack(etcd.FromEtcdError(err)) } if !tresp.Succeeded { walsDataRev := tresp.Responses[0].GetResponseRange().Kvs[0].ModRevision @@ -559,7 +559,7 @@ func (d *DataManager) syncLoop(ctx context.Context) { func (d *DataManager) sync(ctx context.Context) error { session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -569,18 +569,18 @@ func (d *DataManager) sync(ctx context.Context) error { if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0) if err != nil { - return err + return errors.WithStack(err) } for _, kv := range resp.Kvs { var walData WalData if err := json.Unmarshal(kv.Value, &walData); err != nil { - return err + return errors.WithStack(err) } // wals must be committed and checkpointed in order. // TODO(sgotti) this could be optimized by parallelizing writes of wals that don't have common change groups @@ -594,7 +594,7 @@ func (d *DataManager) sync(ctx context.Context) error { } headerj, err := json.Marshal(header) if err != nil { - return err + return errors.WithStack(err) } walFileCommittedPath := walFilePath + ".committed" @@ -606,7 +606,7 @@ func (d *DataManager) sync(ctx context.Context) error { walData.WalStatus = WalStatusCommittedStorage walDataj, err := json.Marshal(walData) if err != nil { - return err + return errors.WithStack(err) } cmp := []etcdclientv3.Cmp{} @@ -619,7 +619,7 @@ func (d *DataManager) sync(ctx context.Context) error { txn := d.e.Client().Txn(ctx).If(cmp...).Then(then...) tresp, err := txn.Commit() if err != nil { - return etcd.FromEtcdError(err) + return errors.WithStack(etcd.FromEtcdError(err)) } if !tresp.Succeeded { return errors.Errorf("failed to write committedstorage wal: concurrent update") @@ -648,7 +648,7 @@ func (d *DataManager) checkpointLoop(ctx context.Context) { func (d *DataManager) checkpoint(ctx context.Context, force bool) error { session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -658,19 +658,19 @@ func (d *DataManager) checkpoint(ctx context.Context, force bool) error { if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0) if err != nil { - return err + return errors.WithStack(err) } walsData := []*WalData{} for _, kv := range resp.Kvs { var walData *WalData if err := json.Unmarshal(kv.Value, &walData); err != nil { - return err + return errors.WithStack(err) } walData.Revision = kv.ModRevision @@ -692,7 +692,7 @@ func (d *DataManager) checkpoint(ctx context.Context, force bool) error { } if err := d.writeDataSnapshot(ctx, walsData); err != nil { - return errors.Errorf("checkpoint function error: %w", err) + return errors.Wrapf(err, "checkpoint function error") } for _, walData := range walsData { @@ -700,11 +700,11 @@ func (d *DataManager) checkpoint(ctx context.Context, force bool) error { walData.WalStatus = WalStatusCheckpointed walDataj, err := json.Marshal(walData) if err != nil { - return err + return errors.WithStack(err) } walKey := etcdWalKey(walData.WalSequence) if _, err := d.e.AtomicPut(ctx, walKey, walDataj, walData.Revision, nil); err != nil { - return err + return errors.WithStack(err) } } @@ -730,7 +730,7 @@ func (d *DataManager) checkpointCleanLoop(ctx context.Context) { func (d *DataManager) checkpointClean(ctx context.Context) error { session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -740,12 +740,12 @@ func (d *DataManager) checkpointClean(ctx context.Context) error { if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() if err := d.CleanOldCheckpoints(ctx); err != nil { - return err + return errors.WithStack(err) } return nil @@ -773,7 +773,7 @@ func (d *DataManager) etcdWalCleanerLoop(ctx context.Context) { func (d *DataManager) etcdWalCleaner(ctx context.Context) error { session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -783,13 +783,13 @@ func (d *DataManager) etcdWalCleaner(ctx context.Context) error { if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0) if err != nil { - return err + return errors.WithStack(err) } if len(resp.Kvs) <= d.etcdWalsKeepNum { return nil @@ -799,7 +799,7 @@ func (d *DataManager) etcdWalCleaner(ctx context.Context) error { for _, kv := range resp.Kvs { var walData WalData if err := json.Unmarshal(kv.Value, &walData); err != nil { - return err + return errors.WithStack(err) } if walData.WalStatus != WalStatusCheckpointed { break @@ -814,7 +814,7 @@ func (d *DataManager) etcdWalCleaner(ctx context.Context) error { // arrive to a differnt S3 server that is not yet in sync? d.log.Info().Msgf("removing wal %q from etcd", walData.WalSequence) if _, err := d.e.AtomicDelete(ctx, string(kv.Key), kv.ModRevision); err != nil { - return err + return errors.WithStack(err) } removeCount-- @@ -846,7 +846,7 @@ func (d *DataManager) storageWalCleanerLoop(ctx context.Context) { func (d *DataManager) storageWalCleaner(ctx context.Context) error { session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -856,13 +856,13 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error { if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() firstDataStatus, err := d.GetFirstDataStatus() if err != nil { - return err + return errors.WithStack(err) } firstWalSequence := firstDataStatus.WalSequence @@ -870,14 +870,14 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error { // it's lesser than the first data status wal sequence resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0) if err != nil { - return err + return errors.WithStack(err) } if len(resp.Kvs) == 0 { return errors.Errorf("no wals in etcd") } var walData WalData if err := json.Unmarshal(resp.Kvs[0].Value, &walData); err != nil { - return err + return errors.WithStack(err) } if walData.WalSequence < firstWalSequence { firstWalSequence = walData.WalSequence @@ -902,7 +902,7 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error { header, err := d.ReadWal(walSequence) if err != nil { - return err + return errors.WithStack(err) } // first remove wal data file @@ -956,7 +956,7 @@ func (d *DataManager) compactChangeGroupsLoop(ctx context.Context) { func (d *DataManager) compactChangeGroups(ctx context.Context) error { session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -966,13 +966,13 @@ func (d *DataManager) compactChangeGroups(ctx context.Context) error { if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() resp, err := d.e.Client().Get(ctx, etcdChangeGroupMinRevisionKey) if err != nil { - return err + return errors.WithStack(err) } if len(resp.Kvs) == 0 { @@ -986,7 +986,8 @@ func (d *DataManager) compactChangeGroups(ctx context.Context) error { txn := d.e.Client().Txn(ctx).If(cmp).Then(then) tresp, err := txn.Commit() if err != nil { - return etcd.FromEtcdError(err) + return errors.WithStack(etcd.FromEtcdError(err)) + } if !tresp.Succeeded { return errors.Errorf("failed to update change group min revision key due to concurrent update") @@ -997,7 +998,7 @@ func (d *DataManager) compactChangeGroups(ctx context.Context) error { // then remove all the groups keys with modrevision < minrevision resp, err = d.e.List(ctx, etcdChangeGroupsDir, "", 0) if err != nil { - return err + return errors.WithStack(err) } for _, kv := range resp.Kvs { if kv.ModRevision < revision-etcdChangeGroupMinRevisionRange { @@ -1006,7 +1007,7 @@ func (d *DataManager) compactChangeGroups(ctx context.Context) error { txn := d.e.Client().Txn(ctx).If(cmp).Then(then) tresp, err := txn.Commit() if err != nil { - return etcd.FromEtcdError(err) + return errors.WithStack(etcd.FromEtcdError(err)) } if !tresp.Succeeded { d.log.Err(err).Msgf("failed to update change group min revision key due to concurrent update") @@ -1040,7 +1041,7 @@ func (d *DataManager) etcdPingerLoop(ctx context.Context) { func (d *DataManager) etcdPinger(ctx context.Context) error { if _, err := d.e.Put(ctx, etcdPingKey, []byte{}, nil); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -1055,7 +1056,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro var header *WalHeader if err = dec.Decode(&header); err != nil && !errors.Is(err, io.EOF) { walFile.Close() - return err + return errors.WithStack(err) } walFile.Close() @@ -1073,7 +1074,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro } walDataj, err := json.Marshal(walData) if err != nil { - return err + return errors.WithStack(err) } cmp := []etcdclientv3.Cmp{} @@ -1084,7 +1085,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro txn := d.e.Client().Txn(ctx).If(cmp...).Then(then...) tresp, err := txn.Commit() if err != nil { - return etcd.FromEtcdError(err) + return errors.WithStack(etcd.FromEtcdError(err)) } if !tresp.Succeeded { return errors.Errorf("failed to sync etcd: wal %q already written", wal.WalSequence) @@ -1094,7 +1095,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -1104,7 +1105,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() @@ -1113,7 +1114,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro _, err = d.e.Get(ctx, etcdWalsDataKey, 0) if err != nil { if !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } mustInit = true } @@ -1123,7 +1124,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro // delete all wals from etcd if err := d.deleteEtcd(ctx); err != nil { - return err + return errors.WithStack(err) } } @@ -1135,7 +1136,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro then = append(then, etcdclientv3.OpPut(etcdChangeGroupMinRevisionKey, "")) txn := d.e.Client().Txn(ctx).If(cmp...).Then(then...) if _, err := txn.Commit(); err != nil { - return etcd.FromEtcdError(err) + return errors.WithStack(etcd.FromEtcdError(err)) } if !mustInit { @@ -1150,7 +1151,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro } else { dataStatus, err = d.GetLastDataStatus() if err != nil && !errors.Is(err, ErrNoDataStatus) { - return err + return errors.WithStack(err) } // set the first wal to import in etcd if there's a snapshot. In this way we'll // ignore older wals (or wals left after an import) @@ -1172,7 +1173,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro } d.log.Debug().Msgf("wal: %s", wal) if wal.Err != nil { - return wal.Err + return errors.WithStack(wal.Err) } if wal.WalSequence < firstWal { @@ -1182,7 +1183,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro lastCommittedStorageWalSequence = wal.WalSequence if err := writeWal(wal, previousWalSequence); err != nil { - return err + return errors.WithStack(err) } previousWalSequence = wal.WalSequence wroteWals++ @@ -1192,7 +1193,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro // insert an empty wal and make it already committedstorage walSequence, err := sequence.IncSequence(ctx, d.e, etcdWalSeqKey) if err != nil { - return err + return errors.WithStack(err) } walDataFileID := uuid.Must(uuid.NewV4()).String() @@ -1212,7 +1213,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro } headerj, err := json.Marshal(header) if err != nil { - return err + return errors.WithStack(err) } walFileCommittedPath := walFilePath + ".committed" if err := d.ost.WriteObject(walFileCommittedPath, bytes.NewReader(headerj), int64(len(headerj)), true); err != nil { @@ -1234,12 +1235,12 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro walDataj, err := json.Marshal(walData) if err != nil { - return err + return errors.WithStack(err) } walsDataj, err := json.Marshal(walsData) if err != nil { - return err + return errors.WithStack(err) } // save walsdata and lastcommittedstoragewalseq only after writing all the @@ -1256,7 +1257,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro txn = d.e.Client().Txn(ctx).If(cmp...).Then(then...) tresp, err := txn.Commit() if err != nil { - return etcd.FromEtcdError(err) + return errors.WithStack(etcd.FromEtcdError(err)) } if !tresp.Succeeded { return errors.Errorf("failed to sync etcd: walsdata already written") @@ -1264,7 +1265,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro // force a checkpoint if err := d.checkpoint(ctx, true); err != nil { - return err + return errors.WithStack(err) } return nil diff --git a/internal/db/create.go b/internal/db/create.go index 62a1bbf..00386a4 100644 --- a/internal/db/create.go +++ b/internal/db/create.go @@ -18,8 +18,8 @@ import ( "context" "database/sql" + "agola.io/agola/internal/errors" sq "github.com/Masterminds/squirrel" - errors "golang.org/x/xerrors" ) const dbVersionTableDDLTmpl = ` @@ -33,22 +33,22 @@ func (db *DB) Create(ctx context.Context, stmts []string) error { err := db.Do(ctx, func(tx *Tx) error { if _, err := tx.Exec(dbVersionTableDDLTmpl); err != nil { - return errors.Errorf("failed to create dbversion table: %w", err) + return errors.Wrapf(err, "failed to create dbversion table") } return nil }) if err != nil { - return err + return errors.WithStack(err) } err = db.Do(ctx, func(tx *Tx) error { var version sql.NullInt64 q, args, err := sb.Select("max(version)").From("dbversion").ToSql() if err != nil { - return err + return errors.WithStack(err) } if err := tx.QueryRow(q, args...).Scan(&version); err != nil { - return errors.Errorf("cannot get current db version: %w", err) + return errors.Wrapf(err, "cannot get current db version") } if version.Valid { return nil @@ -56,18 +56,18 @@ func (db *DB) Create(ctx context.Context, stmts []string) error { for _, stmt := range stmts { if _, err := tx.Exec(stmt); err != nil { - return errors.Errorf("creation failed: %w", err) + return errors.Wrapf(err, "creation failed") } } q, args, err = sb.Insert("dbversion").Columns("version", "time").Values(dbVersion, "now()").ToSql() if err != nil { - return err + return errors.WithStack(err) } if _, err := tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to update dbversion table: %w", err) + return errors.Wrapf(err, "failed to update dbversion table") } return nil }) - return err + return errors.WithStack(err) } diff --git a/internal/db/db.go b/internal/db/db.go index 6ac695c..616b3f2 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -20,8 +20,8 @@ import ( "regexp" "time" + "agola.io/agola/internal/errors" "github.com/mattn/go-sqlite3" - errors "golang.org/x/xerrors" ) type Type string @@ -128,7 +128,7 @@ func NewDB(dbType Type, dbConnString string) (*DB, error) { sqldb, err := sql.Open(driverName, dbConnString) if err != nil { - return nil, err + return nil, errors.WithStack(err) } db := &DB{ @@ -151,11 +151,12 @@ type Tx struct { } func (db *DB) Close() error { - return db.db.Close() + return errors.WithStack(db.db.Close()) } func (db *DB) Conn(ctx context.Context) (*sql.Conn, error) { - return db.db.Conn(ctx) + c, err := db.db.Conn(ctx) + return c, errors.WithStack(err) } func (db *DB) NewUnstartedTx() *Tx { @@ -167,7 +168,7 @@ func (db *DB) NewUnstartedTx() *Tx { func (db *DB) NewTx(ctx context.Context) (*Tx, error) { tx := db.NewUnstartedTx() if err := tx.Start(ctx); err != nil { - return nil, err + return nil, errors.WithStack(err) } return tx, nil @@ -188,14 +189,14 @@ func (db *DB) Do(ctx context.Context, f func(tx *Tx) error) error { } } } - return err + return errors.WithStack(err) } } func (db *DB) do(ctx context.Context, f func(tx *Tx) error) error { tx, err := db.NewTx(ctx) if err != nil { - return err + return errors.WithStack(err) } defer func() { if p := recover(); p != nil { @@ -205,7 +206,7 @@ func (db *DB) do(ctx context.Context, f func(tx *Tx) error) error { }() if err = f(tx); err != nil { _ = tx.Rollback() - return err + return errors.WithStack(err) } return tx.Commit() } @@ -213,12 +214,12 @@ func (db *DB) do(ctx context.Context, f func(tx *Tx) error) error { func (tx *Tx) Start(ctx context.Context) error { wtx, err := tx.db.db.Begin() if err != nil { - return err + return errors.WithStack(err) } switch tx.db.data.t { case Postgres: if _, err := wtx.Exec("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"); err != nil { - return err + return errors.WithStack(err) } } tx.tx = wtx @@ -230,26 +231,26 @@ func (tx *Tx) Commit() error { if tx.tx == nil { return nil } - return tx.tx.Commit() + return errors.WithStack(tx.tx.Commit()) } func (tx *Tx) Rollback() error { if tx.tx == nil { return nil } - return tx.tx.Rollback() + return errors.WithStack(tx.tx.Rollback()) } func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error) { query = tx.db.data.translate(query) r, err := tx.tx.ExecContext(tx.ctx, query, tx.db.data.translateArgs(args)...) - return r, err + return r, errors.WithStack(err) } func (tx *Tx) Query(query string, args ...interface{}) (*sql.Rows, error) { query = tx.db.data.translate(query) r, err := tx.tx.QueryContext(tx.ctx, query, tx.db.data.translateArgs(args)...) - return r, err + return r, errors.WithStack(err) } func (tx *Tx) QueryRow(query string, args ...interface{}) *sql.Row { @@ -262,13 +263,14 @@ func (tx *Tx) CurTime() (time.Time, error) { case Sqlite3: var timestring string if err := tx.QueryRow("select now()").Scan(×tring); err != nil { - return time.Time{}, err + return time.Time{}, errors.WithStack(err) } - return time.ParseInLocation("2006-01-02 15:04:05.999999999", timestring, time.UTC) + t, err := time.ParseInLocation("2006-01-02 15:04:05.999999999", timestring, time.UTC) + return t, errors.WithStack(err) case Postgres: var now time.Time if err := tx.QueryRow("select now()").Scan(&now); err != nil { - return time.Time{}, err + return time.Time{}, errors.WithStack(err) } return now, nil } diff --git a/internal/errors/errors.go b/internal/errors/errors.go new file mode 100644 index 0000000..198216b --- /dev/null +++ b/internal/errors/errors.go @@ -0,0 +1,89 @@ +package errors + +import ( + "fmt" + "io" +) + +type werror struct { + cause error + msg string + *Stack +} + +func (w *werror) Error() string { + if w.cause == nil { + return w.msg + } + if w.msg != "" { + return w.msg + ": " + w.cause.Error() + } else { + return w.cause.Error() + } +} + +func (w *werror) Format(s fmt.State, verb rune) { + _, _ = io.WriteString(s, w.Error()) +} + +func (w *werror) Unwrap() error { return w.cause } + +// New returns an error with the supplied message. +// New also records the stack trace at the point it was called. +func New(message string) error { + return &werror{ + msg: message, + Stack: Callers(0), + } +} + +// Errorf formats according to a format specifier and returns the string +// as a value that satisfies error. +// Errorf also records the stack trace at the point it was called. +func Errorf(format string, args ...interface{}) error { + return &werror{ + msg: fmt.Sprintf(format, args...), + Stack: Callers(0), + } +} + +// WithStack annotates err with a stack trace at the point WithStack was called. +// If err is nil, WithStack returns nil. +func WithStack(err error) error { + if err == nil { + return nil + } + return &werror{ + err, + "", + Callers(0), + } +} + +// Wrap returns an error annotating err with a stack trace +// at the point Wrap is called, and the supplied message. +// If err is nil, Wrap returns nil. +func Wrap(err error, message string) error { + if err == nil { + return nil + } + return &werror{ + err, + message, + Callers(0), + } +} + +// Wrapf returns an error annotating err with a stack trace +// at the point Wrapf is called, and the format specifier. +// If err is nil, Wrapf returns nil. +func Wrapf(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return &werror{ + err, + fmt.Sprintf(format, args...), + Callers(0), + } +} diff --git a/internal/errors/format.go b/internal/errors/format.go new file mode 100644 index 0000000..452f753 --- /dev/null +++ b/internal/errors/format.go @@ -0,0 +1,47 @@ +package errors + +import ( + "errors" + "fmt" +) + +func PrintErrorDetails(err error) []string { + type stackTracer interface { + StackTrace() StackTrace + } + type errWithStack struct { + err error + msg string + stack StackTrace + } + + var stackErrs []errWithStack + errCause := err + for errCause != nil { + stackErr := errWithStack{ + err: errCause, + msg: errCause.Error(), + } + //nolint:errorlint + if s, ok := errCause.(stackTracer); ok { + stackErr.stack = s.StackTrace() + } + stackErrs = append(stackErrs, stackErr) + errCause = errors.Unwrap(errCause) + if err == nil { + break + } + } + + var lines []string + for _, stackErr := range stackErrs { + if len(stackErr.stack) > 0 { + frame := stackErr.stack[0] + lines = append(lines, fmt.Sprintf("(%T) %+v: %s", stackErr.err, frame, stackErr.msg)) + } else { + lines = append(lines, fmt.Sprintf("(%T) %s", stackErr.err, stackErr.msg)) + } + } + + return lines +} diff --git a/internal/errors/go113.go b/internal/errors/go113.go new file mode 100644 index 0000000..be0d10d --- /dev/null +++ b/internal/errors/go113.go @@ -0,0 +1,38 @@ +// +build go1.13 + +package errors + +import ( + stderrors "errors" +) + +// Is reports whether any error in err's chain matches target. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. +func Is(err, target error) bool { return stderrors.Is(err, target) } + +// As finds the first error in err's chain that matches target, and if so, sets +// target to that error value and returns true. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error matches target if the error's concrete value is assignable to the value +// pointed to by target, or if the error has a method As(interface{}) bool such that +// As(target) returns true. In the latter case, the As method is responsible for +// setting target. +// +// As will panic if target is not a non-nil pointer to either a type that implements +// error, or to any interface type. As returns false if err is nil. +func As(err error, target interface{}) bool { return stderrors.As(err, target) } + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +func Unwrap(err error) error { + return stderrors.Unwrap(err) +} diff --git a/internal/errors/stack.go b/internal/errors/stack.go new file mode 100644 index 0000000..7129eff --- /dev/null +++ b/internal/errors/stack.go @@ -0,0 +1,181 @@ +package errors + +import ( + "fmt" + "io" + "path" + "runtime" + "strconv" + "strings" +) + +const ( + defaultSkip = 3 +) + +// Frame represents a program counter inside a stack frame. +// For historical reasons if Frame is interpreted as a uintptr +// its value represents the program counter + 1. +type Frame uintptr + +// pc returns the program counter for this frame; +// multiple frames may have the same PC value. +func (f Frame) pc() uintptr { return uintptr(f) - 1 } + +// file returns the full path to the file that contains the +// function for this Frame's pc. +func (f Frame) file() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + file, _ := fn.FileLine(f.pc()) + return file +} + +// line returns the line number of source code of the +// function for this Frame's pc. +func (f Frame) line() int { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return 0 + } + _, line := fn.FileLine(f.pc()) + return line +} + +// name returns the name of this function, if known. +func (f Frame) name() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + return fn.Name() +} + +// Format formats the frame according to the fmt.Formatter interface. +// +// %s source file +// %d source line +// %n function name +// %v equivalent to %s:%d +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) +// %+v equivalent to %+s:%d +func (f Frame) Format(s fmt.State, verb rune) { + switch verb { + case 's': + switch { + case s.Flag('+'): + _, _ = io.WriteString(s, f.name()) + _, _ = io.WriteString(s, "\n\t") + _, _ = io.WriteString(s, f.file()) + default: + _, _ = io.WriteString(s, path.Base(f.file())) + } + case 'd': + _, _ = io.WriteString(s, strconv.Itoa(f.line())) + case 'n': + _, _ = io.WriteString(s, funcname(f.name())) + case 'v': + f.Format(s, 's') + _, _ = io.WriteString(s, ":") + f.Format(s, 'd') + } +} + +// MarshalText formats a stacktrace Frame as a text string. The output is the +// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs. +func (f Frame) MarshalText() ([]byte, error) { + name := f.name() + if name == "unknown" { + return []byte(name), nil + } + return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil +} + +// StackTrace is stack of Frames from innermost (newest) to outermost (oldest). +type StackTrace []Frame + +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. +func (st StackTrace) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case s.Flag('+'): + for _, f := range st { + _, _ = io.WriteString(s, "\n") + f.Format(s, verb) + } + case s.Flag('#'): + fmt.Fprintf(s, "%#v", []Frame(st)) + default: + st.formatSlice(s, verb) + } + case 's': + st.formatSlice(s, verb) + } +} + +// formatSlice will format this StackTrace into the given buffer as a slice of +// Frame, only valid when called with '%s' or '%v'. +func (st StackTrace) formatSlice(s fmt.State, verb rune) { + _, _ = io.WriteString(s, "[") + for i, f := range st { + if i > 0 { + _, _ = io.WriteString(s, " ") + } + f.Format(s, verb) + } + _, _ = io.WriteString(s, "]") +} + +// Stack represents a Stack of program counters. +type Stack []uintptr + +func (s *Stack) Format(st fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case st.Flag('+'): + for _, pc := range *s { + f := Frame(pc) + fmt.Fprintf(st, "\n%+v", f) + } + } + } +} + +func (s *Stack) StackTrace() StackTrace { + f := make([]Frame, len(*s)) + for i := 0; i < len(f); i++ { + f[i] = Frame((*s)[i]) + } + return f +} + +func Callers(additionalSkip int) *Stack { + const depth = 32 + var pcs [depth]uintptr + n := runtime.Callers(defaultSkip+additionalSkip, pcs[:]) + var st Stack = pcs[0:n] + return &st +} + +// funcname removes the path prefix component of a function's name reported by func.Name(). +func funcname(name string) string { + i := strings.LastIndex(name, "/") + name = name[i+1:] + i = strings.Index(name, ".") + return name[i+1:] +} diff --git a/internal/errors/zerolog.go b/internal/errors/zerolog.go new file mode 100644 index 0000000..efee8c3 --- /dev/null +++ b/internal/errors/zerolog.go @@ -0,0 +1,63 @@ +package errors + +import ( + "encoding/json" + "fmt" + "strings" +) + +// copied from zerolog console writer since they aren't exported +//nolint +const ( + colorBlack = iota + 30 + colorRed + colorGreen + colorYellow + colorBlue + colorMagenta + colorCyan + colorWhite +) + +// colorize returns the string s wrapped in ANSI code c, unless disabled is true. +func colorize(s interface{}, c int, disabled bool) string { + if disabled { + return fmt.Sprintf("%s", s) + } + return fmt.Sprintf("\x1b[%dm%v\x1b[0m", c, s) +} + +type errorFormat = struct { + Error string + Details []string +} + +func FormatErrFieldValue(i interface{}) string { + switch d := i.(type) { + case []byte: + var ed errorFormat + if err := json.Unmarshal(d, &ed); err != nil { + return fmt.Sprintf("error: %v", err) + } + var sb strings.Builder + sb.WriteString(fmt.Sprintf("%s\n", ed.Error)) + if len(ed.Details) > 0 { + sb.WriteString("error details:\n") + for _, l := range ed.Details { + sb.WriteString(fmt.Sprintf("%s\n", l)) + } + } + return colorize(sb.String(), colorRed, false) + + default: + return colorize(fmt.Sprintf("%s", d), colorRed, false) + } +} + +func ErrorMarshalFunc(err error) interface{} { + ef := errorFormat{ + Error: err.Error(), + Details: PrintErrorDetails(err), + } + return ef +} diff --git a/internal/etcd/etcd.go b/internal/etcd/etcd.go index 6fe2355..6ea4db6 100644 --- a/internal/etcd/etcd.go +++ b/internal/etcd/etcd.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" "github.com/rs/zerolog" @@ -29,7 +30,6 @@ import ( etcdclientv3 "go.etcd.io/etcd/clientv3" "go.etcd.io/etcd/clientv3/namespace" "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" - errors "golang.org/x/xerrors" ) var ( @@ -65,7 +65,7 @@ func FromEtcdError(err error) error { if errors.Is(err, rpctypes.ErrKeyNotFound) { return ErrKeyNotFound } - return err + return errors.WithStack(err) } type Store struct { @@ -90,7 +90,7 @@ func New(cfg Config) (*Store, error) { for _, e := range endpoints { u, err := url.Parse(e) if err != nil { - return nil, errors.Errorf("cannot parse endpoint %q: %w", e, err) + return nil, errors.Wrapf(err, "cannot parse endpoint %q", e) } if scheme == "" { scheme = u.Scheme @@ -108,7 +108,7 @@ func New(cfg Config) (*Store, error) { var err error tlsConfig, err = util.NewTLSConfig(cfg.CertFile, cfg.KeyFile, cfg.CAFile, cfg.SkipTLSVerify) if err != nil { - return nil, errors.Errorf("cannot create tls config: %w", err) + return nil, errors.Wrapf(err, "cannot create tls config") } } @@ -119,7 +119,7 @@ func New(cfg Config) (*Store, error) { c, err := etcdclientv3.New(config) if err != nil { - return nil, err + return nil, errors.WithStack(err) } c.KV = namespace.NewKV(c.KV, prefix) @@ -150,7 +150,7 @@ func (s *Store) Put(ctx context.Context, key string, value []byte, options *Writ if options.TTL > 0 { lease, err := s.c.Grant(ctx, int64(options.TTL.Seconds())) if err != nil { - return nil, err + return nil, errors.WithStack(err) } etcdv3Options = append(etcdv3Options, etcdclientv3.WithLease(lease.ID)) } @@ -252,7 +252,7 @@ func (s *Store) AtomicPut(ctx context.Context, key string, value []byte, prevRev if options.TTL > 0 { lease, err := s.c.Grant(ctx, int64(options.TTL)) if err != nil { - return nil, err + return nil, errors.WithStack(err) } etcdv3Options = append(etcdv3Options, etcdclientv3.WithLease(lease.ID)) } @@ -282,7 +282,7 @@ func (s *Store) AtomicPut(ctx context.Context, key string, value []byte, prevRev func (s *Store) Delete(ctx context.Context, key string) error { _, err := s.c.Delete(ctx, key) - return err + return errors.WithStack(err) } func (s *Store) DeletePrefix(ctx context.Context, prefix string) error { @@ -298,7 +298,7 @@ func (s *Store) DeletePrefix(ctx context.Context, prefix string) error { _, err := s.c.Delete(ctx, key, etcdv3Options...) - return err + return errors.WithStack(err) } func (s *Store) AtomicDelete(ctx context.Context, key string, revision int64) (*etcdclientv3.TxnResponse, error) { @@ -333,7 +333,7 @@ func (s *Store) Watch(ctx context.Context, prefix string, revision int64) etcdcl } func (s *Store) Close() error { - return s.c.Close() + return errors.WithStack(s.c.Close()) } func (s *Store) compactor(ctx context.Context, interval time.Duration) { @@ -364,7 +364,7 @@ func (s *Store) compact(ctx context.Context, version, rev int64) (int64, int64, ).Commit() if err != nil { - return version, rev, err + return version, rev, errors.WithStack(err) } curRev := resp.Header.Revision @@ -380,7 +380,7 @@ func (s *Store) compact(ctx context.Context, version, rev int64) (int64, int64, } if _, err = s.c.Compact(ctx, rev); err != nil { s.log.Warn().Msgf("compact error: %v", err) - return curVersion, curRev, err + return curVersion, curRev, errors.WithStack(err) } s.log.Info().Msgf("compacted revision: %d", rev) return curVersion, curRev, nil diff --git a/internal/etcd/mutex.go b/internal/etcd/mutex.go index 1ce40ba..d5142f3 100644 --- a/internal/etcd/mutex.go +++ b/internal/etcd/mutex.go @@ -16,6 +16,7 @@ // have the TryLock function not yet available on stable v3.4 client // Remove this when updating the client to a version providing TryLock +//nolint:wrapcheck package etcd import ( diff --git a/internal/git-handler/handler.go b/internal/git-handler/handler.go index a27b483..c78405a 100644 --- a/internal/git-handler/handler.go +++ b/internal/git-handler/handler.go @@ -24,10 +24,10 @@ import ( "regexp" "strings" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) var ( @@ -109,21 +109,21 @@ func InfoRefsResponse(ctx context.Context, repoPath, serviceName string) ([]byte git := &util.Git{} out, err := git.Output(ctx, nil, serviceName, "--stateless-rpc", "--advertise-refs", repoPath) if err != nil { - return nil, err + return nil, errors.WithStack(err) } buf.Write(out) - return buf.Bytes(), err + return buf.Bytes(), errors.WithStack(err) } func gitService(ctx context.Context, w io.Writer, r io.Reader, repoPath, serviceName string) error { git := &util.Git{GitDir: repoPath} - return git.Pipe(ctx, w, r, serviceName, "--stateless-rpc", repoPath) + return errors.WithStack(git.Pipe(ctx, w, r, serviceName, "--stateless-rpc", repoPath)) } func gitFetchFile(ctx context.Context, w io.Writer, r io.Reader, repoPath, ref, path string) error { git := &util.Git{GitDir: repoPath} - return git.Pipe(ctx, w, r, "show", fmt.Sprintf("%s:%s", ref, path)) + return errors.WithStack(git.Pipe(ctx, w, r, "show", fmt.Sprintf("%s:%s", ref, path))) } var ErrWrongRepoPath = errors.New("wrong repository path") diff --git a/internal/git-save/save.go b/internal/git-save/save.go index 4cec822..315e098 100644 --- a/internal/git-save/save.go +++ b/internal/git-save/save.go @@ -20,11 +20,11 @@ import ( "os" "path/filepath" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" "github.com/gofrs/uuid" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) const ( @@ -35,24 +35,24 @@ const ( func copyFile(src, dest string) error { srcf, err := os.Open(src) if err != nil { - return err + return errors.WithStack(err) } defer srcf.Close() destf, err := os.Create(dest) if err != nil { - return err + return errors.WithStack(err) } defer destf.Close() _, err = io.Copy(destf, srcf) - return err + return errors.WithStack(err) } func fileExists(path string) (bool, error) { _, err := os.Stat(path) if err != nil && !os.IsNotExist(err) { - return false, err + return false, errors.WithStack(err) } return !os.IsNotExist(err), nil } @@ -62,24 +62,24 @@ func GitDir() (string, error) { git := &util.Git{} lines, err := git.OutputLines(context.Background(), nil, "rev-parse", "--git-dir") if err != nil { - return "", err + return "", errors.WithStack(err) } if len(lines) != 1 { return "", errors.Errorf("received %d lines, expected one line", len(lines)) } - return lines[0], err + return lines[0], errors.WithStack(err) } func currentGitBranch() (string, error) { git := &util.Git{} lines, err := git.OutputLines(context.Background(), nil, "symbolic-ref", "--short", "HEAD") if err != nil { - return "", err + return "", errors.WithStack(err) } if len(lines) != 1 { return "", errors.Errorf("received %d lines, expected one line", len(lines)) } - return lines[0], err + return lines[0], errors.WithStack(err) } // gitDir returns the git dir relative to the working dir @@ -87,60 +87,60 @@ func gitWriteTree(indexPath string) (string, error) { git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}} lines, err := git.OutputLines(context.Background(), nil, "write-tree") if err != nil { - return "", err + return "", errors.WithStack(err) } if len(lines) != 1 { return "", errors.Errorf("received %d lines, expected one line", len(lines)) } - return lines[0], err + return lines[0], errors.WithStack(err) } func gitCommitTree(message, treeSHA string) (string, error) { git := &util.Git{} lines, err := git.OutputLines(context.Background(), nil, "commit-tree", "-m", message, treeSHA) if err != nil { - return "", err + return "", errors.WithStack(err) } if len(lines) != 1 { return "", errors.Errorf("received %d lines, expected one line", len(lines)) } - return lines[0], err + return lines[0], errors.WithStack(err) } func gitUpdateRef(message, ref, commitSHA string) error { git := &util.Git{} _, err := git.Output(context.Background(), nil, "update-ref", "-m", message, ref, commitSHA) - return err + return errors.WithStack(err) } func gitUpdateFiles(indexPath string) error { git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}} _, err := git.Output(context.Background(), nil, "add", "-u") - return err + return errors.WithStack(err) } func gitAddUntrackedFiles(indexPath string) error { git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}} _, err := git.Output(context.Background(), nil, "add", ".") - return err + return errors.WithStack(err) } func gitAddIgnoredFiles(indexPath string) error { git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}} _, err := git.Output(context.Background(), nil, "add", "-f", "-A", ".") - return err + return errors.WithStack(err) } func GitAddRemote(configPath, name, url string) error { git := &util.Git{} _, err := git.Output(context.Background(), nil, "remote", "add", name, url) - return err + return errors.WithStack(err) } func GitPush(configPath, remote, branch string) error { git := &util.Git{} _, err := git.Output(context.Background(), nil, "push", remote, branch, "-f") - return err + return errors.WithStack(err) } type GitSaveConfig struct { @@ -178,7 +178,7 @@ func (s *GitSave) RefsPrefix() string { func (s *GitSave) Save(message, branchName string) (string, error) { gitdir, err := GitDir() if err != nil { - return "", err + return "", errors.WithStack(err) } tmpIndexPath := filepath.Join(gitdir, "gitsave-index-"+uuid.Must(uuid.NewV4()).String()) @@ -188,25 +188,25 @@ func (s *GitSave) Save(message, branchName string) (string, error) { curBranch, err := currentGitBranch() if err != nil { - return "", err + return "", errors.WithStack(err) } indexExists, err := fileExists(indexPath) if err != nil { - return "", err + return "", errors.WithStack(err) } if indexExists { // copy current git index to a temporary index if err := copyFile(indexPath, tmpIndexPath); err != nil { - return "", err + return "", errors.WithStack(err) } s.log.Info().Msgf("created temporary index: %s", tmpIndexPath) // read the current branch tree information into the index git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + tmpIndexPath}} _, err = git.Output(context.Background(), nil, "read-tree", curBranch) if err != nil { - return "", err + return "", errors.WithStack(err) } } else { s.log.Info().Msgf("index %s does not exist", indexPath) @@ -214,40 +214,40 @@ func (s *GitSave) Save(message, branchName string) (string, error) { s.log.Info().Msgf("updating files already in the index") if err := gitUpdateFiles(tmpIndexPath); err != nil { - return "", err + return "", errors.WithStack(err) } if s.conf.AddUntracked { s.log.Info().Msgf("adding untracked files") if err := gitAddUntrackedFiles(tmpIndexPath); err != nil { - return "", err + return "", errors.WithStack(err) } } if s.conf.AddIgnored { s.log.Info().Msgf("adding ignored files") if err := gitAddIgnoredFiles(tmpIndexPath); err != nil { - return "", err + return "", errors.WithStack(err) } } s.log.Info().Msgf("writing tree file") treeSHA, err := gitWriteTree(tmpIndexPath) if err != nil { - return "", err + return "", errors.WithStack(err) } s.log.Info().Msgf("tree: %s", treeSHA) s.log.Info().Msgf("committing tree") commitSHA, err := gitCommitTree(message, treeSHA) if err != nil { - return "", err + return "", errors.WithStack(err) } s.log.Info().Msgf("commit: %s", commitSHA) s.log.Info().Msgf("updating ref") if err = gitUpdateRef("git-save", filepath.Join(s.refsPrefix, branchName), commitSHA); err != nil { - return "", err + return "", errors.WithStack(err) } return commitSHA, nil diff --git a/internal/gitsources/agolagit/agolagit.go b/internal/gitsources/agolagit/agolagit.go index 815aaa8..6b2679b 100644 --- a/internal/gitsources/agolagit/agolagit.go +++ b/internal/gitsources/agolagit/agolagit.go @@ -26,6 +26,7 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" "agola.io/agola/internal/services/types" "agola.io/agola/internal/util" @@ -75,29 +76,31 @@ func (c *Client) SetHTTPClient(client *http.Client) { func (c *Client) doRequest(method, path string, query url.Values, header http.Header, ibody io.Reader) (*http.Response, error) { u, err := url.Parse(c.url + "/" + path) if err != nil { - return nil, err + return nil, errors.WithStack(err) } u.RawQuery = query.Encode() req, err := http.NewRequest(method, u.String(), ibody) if err != nil { - return nil, err + return nil, errors.WithStack(err) } for k, v := range header { req.Header[k] = v } - return c.client.Do(req) + res, err := c.client.Do(req) + + return res, errors.WithStack(err) } func (c *Client) getResponse(method, path string, query url.Values, header http.Header, ibody io.Reader) (*http.Response, error) { resp, err := c.doRequest(method, path, query, header, ibody) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := util.ErrFromRemote(resp); err != nil { - return resp, err + return resp, errors.WithStack(err) } return resp, nil @@ -114,12 +117,12 @@ func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) { func (c *Client) GetFile(repopath, commit, file string) ([]byte, error) { resp, err := c.getResponse("GET", fmt.Sprintf("%s.git/raw/%s/%s", repopath, commit, file), nil, nil, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer resp.Body.Close() data, err := ioutil.ReadAll(resp.Body) - return data, err + return data, errors.WithStack(err) } func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) error { @@ -174,7 +177,7 @@ func (c *Client) RefType(ref string) (gitsource.RefType, string, error) { } } - return -1, "", fmt.Errorf("unsupported ref: %s", ref) + return -1, "", errors.Errorf("unsupported ref: %s", ref) } func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) { diff --git a/internal/gitsources/gitea/gitea.go b/internal/gitsources/gitea/gitea.go index 9b0e252..1897581 100644 --- a/internal/gitsources/gitea/gitea.go +++ b/internal/gitsources/gitea/gitea.go @@ -28,11 +28,11 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" "code.gitea.io/sdk/gitea" "golang.org/x/oauth2" - errors "golang.org/x/xerrors" ) const ( @@ -146,7 +146,7 @@ func (c *Client) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, er var config = c.oauth2Config(callbackURL) token, err := config.Exchange(ctx, code) if err != nil { - return nil, errors.Errorf("cannot get oauth2 token: %w", err) + return nil, errors.Wrapf(err, "cannot get oauth2 token") } return token, nil } @@ -158,7 +158,9 @@ func (c *Client) RefreshOauth2Token(refreshToken string) (*oauth2.Token, error) var config = c.oauth2Config("") token := &oauth2.Token{RefreshToken: refreshToken} ts := config.TokenSource(ctx, token) - return ts.Token() + ntoken, err := ts.Token() + + return ntoken, errors.WithStack(err) } func (c *Client) LoginPassword(username, password, tokenName string) (string, error) { @@ -172,16 +174,16 @@ func (c *Client) LoginPassword(username, password, tokenName string) (string, er tokens := make([]*gitea.AccessToken, 0, 10) req, err := http.NewRequest("GET", c.APIURL+"/api/v1"+fmt.Sprintf("/users/%s/tokens", username), nil) if err != nil { - return "", err + return "", errors.WithStack(err) } req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(username+":"+password))) resp, err := c.oauth2HTTPClient.Do(req) if err != nil { - return "", err + return "", errors.WithStack(err) } if resp.StatusCode == http.StatusUnauthorized { - return "", gitsource.ErrUnauthorized + return "", errors.WithStack(gitsource.ErrUnauthorized) } if resp.StatusCode/100 != 2 { return "", errors.Errorf("gitea api status code %d", resp.StatusCode) @@ -190,7 +192,7 @@ func (c *Client) LoginPassword(username, password, tokenName string) (string, er dec := json.NewDecoder(resp.Body) if err := dec.Decode(&tokens); err != nil { - return "", err + return "", errors.WithStack(err) } for _, token := range tokens { if token.Name == tokenName { @@ -206,7 +208,7 @@ func (c *Client) LoginPassword(username, password, tokenName string) (string, er gitea.CreateAccessTokenOption{Name: tokenName}, ) if terr != nil { - return "", terr + return "", errors.WithStack(terr) } accessToken = token.Token } @@ -217,7 +219,7 @@ func (c *Client) LoginPassword(username, password, tokenName string) (string, er func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { user, err := c.client.GetMyUserInfo() if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &gitsource.UserInfo{ ID: strconv.FormatInt(user.ID, 10), @@ -229,11 +231,11 @@ func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return nil, err + return nil, errors.WithStack(err) } rr, err := c.client.GetRepo(owner, reponame) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return fromGiteaRepo(rr), nil } @@ -241,23 +243,23 @@ func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) { func (c *Client) GetFile(repopath, commit, file string) ([]byte, error) { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return nil, err + return nil, errors.WithStack(err) } data, err := c.client.GetFile(owner, reponame, commit, file) - return data, err + return data, errors.WithStack(err) } func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } if _, err = c.client.CreateDeployKey(owner, reponame, gitea.CreateKeyOption{ Title: title, Key: pubKey, ReadOnly: readonly, }); err != nil { - return errors.Errorf("error creating deploy key: %w", err) + return errors.Wrapf(err, "error creating deploy key") } return nil @@ -266,7 +268,7 @@ func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } // NOTE(sgotti) gitea has a bug where if we delete and remove the same key with // the same value it is correctly readded and the admin must force a @@ -274,7 +276,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) // when the public key value has changed keys, err := c.client.ListDeployKeys(owner, reponame, gitea.ListDeployKeysOptions{}) if err != nil { - return errors.Errorf("error retrieving existing deploy keys: %w", err) + return errors.Wrapf(err, "error retrieving existing deploy keys") } for _, key := range keys { @@ -283,7 +285,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) return nil } if err := c.client.DeleteDeployKey(owner, reponame, key.ID); err != nil { - return errors.Errorf("error removing existing deploy key: %w", err) + return errors.Wrapf(err, "error removing existing deploy key") } } } @@ -293,7 +295,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) Key: pubKey, ReadOnly: readonly, }); err != nil { - return errors.Errorf("error creating deploy key: %w", err) + return errors.Wrapf(err, "error creating deploy key") } return nil @@ -302,17 +304,17 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) func (c *Client) DeleteDeployKey(repopath, title string) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } keys, err := c.client.ListDeployKeys(owner, reponame, gitea.ListDeployKeysOptions{}) if err != nil { - return errors.Errorf("error retrieving existing deploy keys: %w", err) + return errors.Wrapf(err, "error retrieving existing deploy keys") } for _, key := range keys { if key.Title == title { if err := c.client.DeleteDeployKey(owner, reponame, key.ID); err != nil { - return errors.Errorf("error removing existing deploy key: %w", err) + return errors.Wrapf(err, "error removing existing deploy key") } } } @@ -323,7 +325,7 @@ func (c *Client) DeleteDeployKey(repopath, title string) error { func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } opts := gitea.CreateHookOption{ @@ -338,7 +340,7 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { } if _, err = c.client.CreateRepoHook(owner, reponame, opts); err != nil { - return errors.Errorf("error creating repository webhook: %w", err) + return errors.Wrapf(err, "error creating repository webhook") } return nil @@ -347,11 +349,11 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { func (c *Client) DeleteRepoWebhook(repopath, u string) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } hooks, err := c.client.ListRepoHooks(owner, reponame, gitea.ListHooksOptions{}) if err != nil { - return errors.Errorf("error retrieving repository webhooks: %w", err) + return errors.Wrapf(err, "error retrieving repository webhooks") } // match the full url so we can have multiple webhooks for different agola @@ -359,7 +361,7 @@ func (c *Client) DeleteRepoWebhook(repopath, u string) error { for _, hook := range hooks { if hook.Config["url"] == u { if err := c.client.DeleteRepoHook(owner, reponame, hook.ID); err != nil { - return errors.Errorf("error deleting existing repository webhook: %w", err) + return errors.Wrapf(err, "error deleting existing repository webhook") } } } @@ -370,7 +372,7 @@ func (c *Client) DeleteRepoWebhook(repopath, u string) error { func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource.CommitStatus, targetURL, description, context string) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } _, err = c.client.CreateStatus(owner, reponame, commitSHA, gitea.CreateStatusOption{ State: fromCommitStatus(status), @@ -378,7 +380,7 @@ func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource Description: description, Context: context, }) - return err + return errors.WithStack(err) } func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { @@ -396,7 +398,7 @@ func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { ) if err != nil { - return []*gitsource.RepoInfo{}, err + return []*gitsource.RepoInfo{}, errors.WithStack(err) } for _, repo := range remoteRepos { @@ -429,12 +431,12 @@ func fromGiteaRepo(rr *gitea.Repository) *gitsource.RepoInfo { func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return nil, err + return nil, errors.WithStack(err) } remoteRefs, err := c.client.GetRepoRefs(owner, reponame, ref) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(remoteRefs) == 0 { return nil, errors.Errorf("no ref %q for repository %q", ref, repopath) @@ -480,12 +482,12 @@ func (c *Client) RefType(ref string) (gitsource.RefType, string, error) { func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return nil, err + return nil, errors.WithStack(err) } commit, err := c.client.GetSingleCommit(owner, reponame, commitSHA) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &gitsource.Commit{ diff --git a/internal/gitsources/gitea/parse.go b/internal/gitsources/gitea/parse.go index 9814b9d..ab99bdd 100644 --- a/internal/gitsources/gitea/parse.go +++ b/internal/gitsources/gitea/parse.go @@ -27,9 +27,8 @@ import ( "strconv" "strings" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/types" - - errors "golang.org/x/xerrors" ) const ( @@ -48,7 +47,7 @@ const ( func (c *Client) ParseWebhook(r *http.Request, secret string) (*types.WebhookData, error) { data, err := ioutil.ReadAll(io.LimitReader(r.Body, 10*1024*1024)) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // verify signature @@ -83,7 +82,7 @@ func parsePushHook(data []byte) (*types.WebhookData, error) { push := new(pushHook) err := json.Unmarshal(data, push) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return webhookDataFromPush(push) @@ -93,7 +92,7 @@ func parsePullRequestHook(data []byte) (*types.WebhookData, error) { prhook := new(pullRequestHook) err := json.Unmarshal(data, prhook) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // skip non open pull requests @@ -144,7 +143,7 @@ func webhookDataFromPush(hook *pushHook) (*types.WebhookData, error) { whd.Message = fmt.Sprintf("Tag %s", whd.Tag) default: // ignore received webhook since it doesn't have a ref we're interested in - return nil, fmt.Errorf("unsupported webhook ref %q", hook.Ref) + return nil, errors.Errorf("unsupported webhook ref %q", hook.Ref) } return whd, nil diff --git a/internal/gitsources/github/github.go b/internal/gitsources/github/github.go index 1c8cfcb..167b788 100644 --- a/internal/gitsources/github/github.go +++ b/internal/gitsources/github/github.go @@ -28,11 +28,11 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" "github.com/google/go-github/v29/github" "golang.org/x/oauth2" - errors "golang.org/x/xerrors" ) var ( @@ -81,7 +81,7 @@ func fromCommitStatus(status gitsource.CommitStatus) string { case gitsource.CommitStatusFailed: return "failure" default: - panic(fmt.Errorf("unknown commit status %q", status)) + panic(errors.Errorf("unknown commit status %q", status)) } } @@ -102,6 +102,8 @@ func (t *TokenTransport) RoundTrip(r *http.Request) (*http.Response, error) { if t.token != "" { r.Header.Set("Authorization", "Bearer "+t.token) } + + //nolint:wrapcheck return t.rt.RoundTrip(r) } @@ -184,7 +186,7 @@ func (c *Client) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, er var config = c.oauth2Config(callbackURL) token, err := config.Exchange(ctx, code) if err != nil { - return nil, errors.Errorf("cannot get oauth2 token: %w", err) + return nil, errors.Wrapf(err, "cannot get oauth2 token") } return token, nil } @@ -196,13 +198,15 @@ func (c *Client) RefreshOauth2Token(refreshToken string) (*oauth2.Token, error) var config = c.oauth2Config("") token := &oauth2.Token{RefreshToken: refreshToken} ts := config.TokenSource(ctx, token) - return ts.Token() + ntoken, err := ts.Token() + + return ntoken, errors.WithStack(err) } func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { user, _, err := c.client.Users.Get(context.TODO(), "") if err != nil { - return nil, err + return nil, errors.WithStack(err) } userInfo := &gitsource.UserInfo{ @@ -219,11 +223,11 @@ func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return nil, err + return nil, errors.WithStack(err) } rr, _, err := c.client.Repositories.Get(context.TODO(), owner, reponame) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return fromGithubRepo(rr), nil } @@ -231,28 +235,29 @@ func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) { func (c *Client) GetFile(repopath, commit, file string) ([]byte, error) { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return nil, err + return nil, errors.WithStack(err) } r, err := c.client.Repositories.DownloadContents(context.TODO(), owner, reponame, file, &github.RepositoryContentGetOptions{Ref: commit}) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer r.Close() - return ioutil.ReadAll(r) + d, err := ioutil.ReadAll(r) + return d, errors.WithStack(err) } func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } if _, _, err = c.client.Repositories.CreateKey(context.TODO(), owner, reponame, &github.Key{ Title: github.String(title), Key: github.String(pubKey), ReadOnly: github.Bool(readonly), }); err != nil { - return errors.Errorf("error creating deploy key: %w", err) + return errors.Wrapf(err, "error creating deploy key") } return nil } @@ -260,7 +265,7 @@ func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } // NOTE(sgotti) gitea has a bug where if we delete and remove the same key with // the same value it is correctly readded and the admin must force a @@ -268,7 +273,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) // when the public key value has changed keys, _, err := c.client.Repositories.ListKeys(context.TODO(), owner, reponame, nil) if err != nil { - return errors.Errorf("error retrieving existing deploy keys: %w", err) + return errors.Wrapf(err, "error retrieving existing deploy keys") } for _, key := range keys { @@ -277,7 +282,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) return nil } if _, err := c.client.Repositories.DeleteKey(context.TODO(), owner, reponame, *key.ID); err != nil { - return errors.Errorf("error removing existing deploy key: %w", err) + return errors.Wrapf(err, "error removing existing deploy key") } } } @@ -287,7 +292,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) Key: github.String(pubKey), ReadOnly: github.Bool(readonly), }); err != nil { - return errors.Errorf("error creating deploy key: %w", err) + return errors.Wrapf(err, "error creating deploy key") } return nil @@ -296,17 +301,17 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) func (c *Client) DeleteDeployKey(repopath, title string) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } keys, _, err := c.client.Repositories.ListKeys(context.TODO(), owner, reponame, nil) if err != nil { - return errors.Errorf("error retrieving existing deploy keys: %w", err) + return errors.Wrapf(err, "error retrieving existing deploy keys") } for _, key := range keys { if *key.Title == title { if _, err := c.client.Repositories.DeleteKey(context.TODO(), owner, reponame, *key.ID); err != nil { - return errors.Errorf("error removing existing deploy key: %w", err) + return errors.Wrapf(err, "error removing existing deploy key") } } } @@ -317,7 +322,7 @@ func (c *Client) DeleteDeployKey(repopath, title string) error { func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } hook := &github.Hook{ @@ -331,7 +336,7 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { } if _, _, err = c.client.Repositories.CreateHook(context.TODO(), owner, reponame, hook); err != nil { - return errors.Errorf("error creating repository webhook: %w", err) + return errors.Wrapf(err, "error creating repository webhook") } return nil @@ -340,7 +345,7 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { func (c *Client) DeleteRepoWebhook(repopath, u string) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } hooks := []*github.Hook{} @@ -349,7 +354,7 @@ func (c *Client) DeleteRepoWebhook(repopath, u string) error { for { pHooks, resp, err := c.client.Repositories.ListHooks(context.TODO(), owner, reponame, opt) if err != nil { - return errors.Errorf("error retrieving repository webhooks: %w", err) + return errors.Wrapf(err, "error retrieving repository webhooks") } hooks = append(hooks, pHooks...) if resp.NextPage == 0 { @@ -363,7 +368,7 @@ func (c *Client) DeleteRepoWebhook(repopath, u string) error { for _, hook := range hooks { if hook.Config["url"] == u { if _, err := c.client.Repositories.DeleteHook(context.TODO(), owner, reponame, *hook.ID); err != nil { - return errors.Errorf("error deleting existing repository webhook: %w", err) + return errors.Wrapf(err, "error deleting existing repository webhook") } } } @@ -374,7 +379,7 @@ func (c *Client) DeleteRepoWebhook(repopath, u string) error { func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource.CommitStatus, targetURL, description, statusContext string) error { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return err + return errors.WithStack(err) } _, _, err = c.client.Repositories.CreateStatus(context.TODO(), owner, reponame, commitSHA, &github.RepoStatus{ State: github.String(fromCommitStatus(status)), @@ -382,7 +387,7 @@ func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource Description: github.String(description), Context: github.String(statusContext), }) - return err + return errors.WithStack(err) } func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { @@ -392,7 +397,7 @@ func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { for { pRemoteRepos, resp, err := c.client.Repositories.List(context.TODO(), "", opt) if err != nil { - return nil, err + return nil, errors.WithStack(err) } remoteRepos = append(remoteRepos, pRemoteRepos...) if resp.NextPage == 0 { @@ -429,12 +434,12 @@ func fromGithubRepo(rr *github.Repository) *gitsource.RepoInfo { func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return nil, err + return nil, errors.WithStack(err) } remoteRef, _, err := c.client.Git.GetRef(context.TODO(), owner, reponame, ref) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return fromGithubRef(remoteRef) @@ -445,7 +450,7 @@ func fromGithubRef(remoteRef *github.Reference) (*gitsource.Ref, error) { switch t { case "commit": default: - return nil, fmt.Errorf("unsupported object type: %s", t) + return nil, errors.Errorf("unsupported object type: %s", t) } return &gitsource.Ref{ @@ -467,19 +472,19 @@ func (c *Client) RefType(ref string) (gitsource.RefType, string, error) { return gitsource.RefTypePullRequest, m[1], nil default: - return -1, "", fmt.Errorf("unsupported ref: %s", ref) + return -1, "", errors.Errorf("unsupported ref: %s", ref) } } func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) { owner, reponame, err := parseRepoPath(repopath) if err != nil { - return nil, err + return nil, errors.WithStack(err) } commit, _, err := c.client.Git.GetCommit(context.TODO(), owner, reponame, commitSHA) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &gitsource.Commit{ diff --git a/internal/gitsources/github/parse.go b/internal/gitsources/github/parse.go index d14732e..d904cf5 100644 --- a/internal/gitsources/github/parse.go +++ b/internal/gitsources/github/parse.go @@ -21,10 +21,10 @@ import ( "strconv" "strings" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/types" "github.com/google/go-github/v29/github" - errors "golang.org/x/xerrors" ) const ( @@ -37,12 +37,12 @@ const ( func (c *Client) ParseWebhook(r *http.Request, secret string) (*types.WebhookData, error) { payload, err := github.ValidatePayload(r, []byte(secret)) if err != nil { - return nil, errors.Errorf("wrong webhook signature: %w", err) + return nil, errors.Wrapf(err, "wrong webhook signature") } webHookType := github.WebHookType(r) event, err := github.ParseWebHook(webHookType, payload) if err != nil { - return nil, errors.Errorf("failed to parse webhook: %w", err) + return nil, errors.Wrapf(err, "failed to parse webhook") } switch event := event.(type) { case *github.PushEvent: @@ -96,7 +96,7 @@ func webhookDataFromPush(hook *github.PushEvent) (*types.WebhookData, error) { default: // ignore received webhook since it doesn't have a ref we're interested in - return nil, fmt.Errorf("unsupported webhook ref %q", *hook.Ref) + return nil, errors.Errorf("unsupported webhook ref %q", *hook.Ref) } return whd, nil diff --git a/internal/gitsources/gitlab/gitlab.go b/internal/gitsources/gitlab/gitlab.go index f9edda0..682a962 100644 --- a/internal/gitsources/gitlab/gitlab.go +++ b/internal/gitsources/gitlab/gitlab.go @@ -26,11 +26,11 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" gitlab "github.com/xanzy/go-gitlab" "golang.org/x/oauth2" - errors "golang.org/x/xerrors" ) var ( @@ -70,7 +70,7 @@ func fromCommitStatus(status gitsource.CommitStatus) gitlab.BuildStateValue { case gitsource.CommitStatusFailed: return gitlab.Failed default: - panic(fmt.Errorf("unknown commit status %q", status)) + panic(errors.Errorf("unknown commit status %q", status)) } } @@ -93,7 +93,7 @@ func New(opts Opts) (*Client, error) { client := gitlab.NewOAuthClient(httpClient, opts.Token) if err := client.SetBaseURL(opts.APIURL); err != nil { - return nil, errors.Errorf("failed to set gitlab client base url: %w", err) + return nil, errors.Wrapf(err, "failed to set gitlab client base url") } return &Client{ @@ -130,7 +130,7 @@ func (c *Client) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, er var config = c.oauth2Config(callbackURL) token, err := config.Exchange(ctx, code) if err != nil { - return nil, errors.Errorf("cannot get oauth2 token: %w", err) + return nil, errors.Wrapf(err, "cannot get oauth2 token") } return token, nil } @@ -142,13 +142,15 @@ func (c *Client) RefreshOauth2Token(refreshToken string) (*oauth2.Token, error) var config = c.oauth2Config("") token := &oauth2.Token{RefreshToken: refreshToken} ts := config.TokenSource(ctx, token) - return ts.Token() + ntoken, err := ts.Token() + + return ntoken, errors.WithStack(err) } func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) { rr, _, err := c.client.Projects.GetProject(repopath, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return fromGitlabRepo(rr), nil } @@ -156,7 +158,7 @@ func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) { func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { user, _, err := c.client.Users.CurrentUser() if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &gitsource.UserInfo{ ID: strconv.Itoa(user.ID), @@ -168,13 +170,13 @@ func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { func (c *Client) GetFile(repopath, commit, file string) ([]byte, error) { f, _, err := c.client.RepositoryFiles.GetFile(repopath, file, &gitlab.GetFileOptions{Ref: gitlab.String(commit)}) if err != nil { - return nil, err + return nil, errors.WithStack(err) } data, err := base64.StdEncoding.DecodeString(f.Content) if err != nil { - return nil, err + return nil, errors.WithStack(err) } - return data, err + return data, errors.WithStack(err) } func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) error { @@ -182,7 +184,7 @@ func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) Title: gitlab.String(title), Key: gitlab.String(pubKey), }); err != nil { - return errors.Errorf("error creating deploy key: %w", err) + return errors.Wrapf(err, "error creating deploy key") } return nil @@ -191,7 +193,7 @@ func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) error { keys, _, err := c.client.DeployKeys.ListProjectDeployKeys(repopath, nil) if err != nil { - return errors.Errorf("error retrieving existing deploy keys: %w", err) + return errors.Wrapf(err, "error retrieving existing deploy keys") } for _, key := range keys { @@ -200,7 +202,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) return nil } if _, err := c.client.DeployKeys.DeleteDeployKey(repopath, key.ID); err != nil { - return errors.Errorf("error removing existing deploy key: %w", err) + return errors.Wrapf(err, "error removing existing deploy key") } } } @@ -209,7 +211,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) Title: &title, Key: &pubKey, }); err != nil { - return errors.Errorf("error creating deploy key: %w", err) + return errors.Wrapf(err, "error creating deploy key") } return nil @@ -218,13 +220,13 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) func (c *Client) DeleteDeployKey(repopath, title string) error { keys, _, err := c.client.DeployKeys.ListProjectDeployKeys(repopath, nil) if err != nil { - return errors.Errorf("error retrieving existing deploy keys: %w", err) + return errors.Wrapf(err, "error retrieving existing deploy keys") } for _, key := range keys { if key.Title == title { if _, err := c.client.DeployKeys.DeleteDeployKey(repopath, key.ID); err != nil { - return errors.Errorf("error removing existing deploy key: %w", err) + return errors.Wrapf(err, "error removing existing deploy key") } } } @@ -241,7 +243,7 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { Token: gitlab.String(secret), } if _, _, err := c.client.Projects.AddProjectHook(repopath, opts); err != nil { - return errors.Errorf("error creating repository webhook: %w", err) + return errors.Wrapf(err, "error creating repository webhook") } return nil @@ -250,7 +252,7 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { func (c *Client) DeleteRepoWebhook(repopath, u string) error { hooks, _, err := c.client.Projects.ListProjectHooks(repopath, nil) if err != nil { - return errors.Errorf("error retrieving repository webhooks: %w", err) + return errors.Wrapf(err, "error retrieving repository webhooks") } // match the full url so we can have multiple webhooks for different agola @@ -258,7 +260,7 @@ func (c *Client) DeleteRepoWebhook(repopath, u string) error { for _, hook := range hooks { if hook.URL == u { if _, err := c.client.Projects.DeleteProjectHook(repopath, hook.ID); err != nil { - return errors.Errorf("error deleting existing repository webhook: %w", err) + return errors.Wrapf(err, "error deleting existing repository webhook") } } } @@ -273,7 +275,7 @@ func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource Description: gitlab.String(description), Context: gitlab.String(context), }) - return err + return errors.WithStack(err) } func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { @@ -281,7 +283,7 @@ func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { opts := &gitlab.ListProjectsOptions{MinAccessLevel: gitlab.AccessLevel(gitlab.MaintainerPermissions)} remoteRepos, _, err := c.client.Projects.ListProjects(opts) if err != nil { - return nil, err + return nil, errors.WithStack(err) } repos := []*gitsource.RepoInfo{} @@ -311,7 +313,7 @@ func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) { branch := strings.TrimPrefix(ref, "refs/heads/") remoteBranch, _, err := c.client.Branches.GetBranch(repopath, branch) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &gitsource.Ref{ @@ -323,7 +325,7 @@ func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) { tag := strings.TrimPrefix(ref, "refs/heads/") remoteTag, _, err := c.client.Tags.GetTag(repopath, tag) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &gitsource.Ref{ @@ -331,7 +333,7 @@ func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) { CommitSHA: remoteTag.Commit.ID, }, nil default: - return nil, fmt.Errorf("unsupported ref: %s", ref) + return nil, errors.Errorf("unsupported ref: %s", ref) } } @@ -348,14 +350,14 @@ func (c *Client) RefType(ref string) (gitsource.RefType, string, error) { return gitsource.RefTypePullRequest, m[1], nil default: - return -1, "", fmt.Errorf("unsupported ref: %s", ref) + return -1, "", errors.Errorf("unsupported ref: %s", ref) } } func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) { commit, _, err := c.client.Commits.GetCommit(repopath, commitSHA, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &gitsource.Commit{ diff --git a/internal/gitsources/gitlab/parse.go b/internal/gitsources/gitlab/parse.go index c43e4d9..6ca998b 100644 --- a/internal/gitsources/gitlab/parse.go +++ b/internal/gitsources/gitlab/parse.go @@ -23,9 +23,8 @@ import ( "strconv" "strings" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/types" - - errors "golang.org/x/xerrors" ) const ( @@ -40,7 +39,7 @@ const ( func (c *Client) ParseWebhook(r *http.Request, secret string) (*types.WebhookData, error) { data, err := ioutil.ReadAll(io.LimitReader(r.Body, 10*1024*1024)) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // verify token (gitlab doesn't sign the payload but just returns the provided @@ -68,7 +67,7 @@ func parsePushHook(data []byte) (*types.WebhookData, error) { push := new(pushHook) err := json.Unmarshal(data, push) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // skip push events with 0 commits. i.e. a tag deletion. @@ -83,7 +82,7 @@ func parsePullRequestHook(data []byte) (*types.WebhookData, error) { prhook := new(pullRequestHook) err := json.Unmarshal(data, prhook) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // TODO(sgotti) skip non open pull requests @@ -127,7 +126,7 @@ func webhookDataFromPush(hook *pushHook) (*types.WebhookData, error) { whd.Message = fmt.Sprintf("Tag %s", whd.Tag) default: // ignore received webhook since it doesn't have a ref we're interested in - return nil, fmt.Errorf("unsupported webhook ref %q", hook.Ref) + return nil, errors.Errorf("unsupported webhook ref %q", hook.Ref) } return whd, nil diff --git a/internal/gitsources/gitsource.go b/internal/gitsources/gitsource.go index f93c95a..a1679b5 100644 --- a/internal/gitsources/gitsource.go +++ b/internal/gitsources/gitsource.go @@ -15,10 +15,11 @@ package gitsource import ( - "errors" "net/http" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/types" + "golang.org/x/oauth2" ) diff --git a/internal/objectstorage/atomic.go b/internal/objectstorage/atomic.go index b0a5c32..fd82ea5 100644 --- a/internal/objectstorage/atomic.go +++ b/internal/objectstorage/atomic.go @@ -20,6 +20,8 @@ import ( "os" "path/filepath" "strings" + + "agola.io/agola/internal/errors" ) // writeFileAtomicFunc atomically writes a file, it achieves this by creating a @@ -30,7 +32,7 @@ import ( func writeFileAtomicFunc(p, baseDir, tmpDir string, perm os.FileMode, persist bool, writeFunc func(f io.Writer) error) error { f, err := ioutil.TempFile(tmpDir, "tmpfile") if err != nil { - return err + return errors.WithStack(err) } err = writeFunc(f) if persist && err == nil { @@ -47,7 +49,7 @@ func writeFileAtomicFunc(p, baseDir, tmpDir string, perm os.FileMode, persist bo } if err != nil { os.Remove(f.Name()) - return err + return errors.WithStack(err) } if !persist { @@ -80,7 +82,7 @@ func writeFileAtomic(filename, baseDir, tmpDir string, perm os.FileMode, persist return writeFileAtomicFunc(filename, baseDir, tmpDir, perm, persist, func(f io.Writer) error { _, err := f.Write(data) - return err + return errors.WithStack(err) }) } */ diff --git a/internal/objectstorage/objectstorage.go b/internal/objectstorage/objectstorage.go index e4aefcf..ab5278e 100644 --- a/internal/objectstorage/objectstorage.go +++ b/internal/objectstorage/objectstorage.go @@ -18,7 +18,7 @@ import ( "io" "time" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/errors" ) type Storage interface { @@ -36,10 +36,12 @@ type Storage interface { type ErrNotExist struct { err error + + *errors.Stack } func NewErrNotExist(err error) error { - return &ErrNotExist{err: err} + return &ErrNotExist{err: err, Stack: errors.Callers(0)} } func (e *ErrNotExist) Error() string { diff --git a/internal/objectstorage/posix.go b/internal/objectstorage/posix.go index 348050a..55f4205 100644 --- a/internal/objectstorage/posix.go +++ b/internal/objectstorage/posix.go @@ -21,7 +21,7 @@ import ( "path/filepath" "strings" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/errors" ) const ( @@ -36,15 +36,15 @@ type PosixStorage struct { func NewPosix(baseDir string) (*PosixStorage, error) { if err := os.MkdirAll(baseDir, 0770); err != nil { - return nil, err + return nil, errors.WithStack(err) } dataDir := filepath.Join(baseDir, dataDirName) tmpDir := filepath.Join(baseDir, tmpDirName) if err := os.MkdirAll(dataDir, 0770); err != nil { - return nil, errors.Errorf("failed to create data dir: %w", err) + return nil, errors.Wrapf(err, "failed to create data dir") } if err := os.MkdirAll(tmpDir, 0770); err != nil { - return nil, errors.Errorf("failed to create tmp dir: %w", err) + return nil, errors.Wrapf(err, "failed to create tmp dir") } return &PosixStorage{ dataDir: dataDir, @@ -59,7 +59,7 @@ func (s *PosixStorage) fsPath(p string) (string, error) { func (s *PosixStorage) Stat(p string) (*ObjectInfo, error) { fspath, err := s.fsPath(p) if err != nil { - return nil, err + return nil, errors.WithStack(err) } fi, err := os.Stat(fspath) @@ -67,7 +67,7 @@ func (s *PosixStorage) Stat(p string) (*ObjectInfo, error) { if os.IsNotExist(err) { return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) } - return nil, err + return nil, errors.WithStack(err) } return &ObjectInfo{Path: p, LastModified: fi.ModTime(), Size: fi.Size()}, nil @@ -76,24 +76,24 @@ func (s *PosixStorage) Stat(p string) (*ObjectInfo, error) { func (s *PosixStorage) ReadObject(p string) (ReadSeekCloser, error) { fspath, err := s.fsPath(p) if err != nil { - return nil, err + return nil, errors.WithStack(err) } f, err := os.Open(fspath) if err != nil && os.IsNotExist(err) { return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) } - return f, err + return f, errors.WithStack(err) } func (s *PosixStorage) WriteObject(p string, data io.Reader, size int64, persist bool) error { fspath, err := s.fsPath(p) if err != nil { - return err + return errors.WithStack(err) } if err := os.MkdirAll(path.Dir(fspath), 0770); err != nil { - return err + return errors.WithStack(err) } r := data @@ -102,21 +102,21 @@ func (s *PosixStorage) WriteObject(p string, data io.Reader, size int64, persist } return writeFileAtomicFunc(fspath, s.dataDir, s.tmpDir, 0660, persist, func(f io.Writer) error { _, err := io.Copy(f, r) - return err + return errors.WithStack(err) }) } func (s *PosixStorage) DeleteObject(p string) error { fspath, err := s.fsPath(p) if err != nil { - return err + return errors.WithStack(err) } if err := os.Remove(fspath); err != nil { if os.IsNotExist(err) { return NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) } - return err + return errors.WithStack(err) } // try to remove parent empty dirs @@ -179,7 +179,7 @@ func (s *PosixStorage) List(prefix, startWith, delimiter string, doneCh <-chan s defer close(objectCh) err := filepath.Walk(root, func(ep string, info os.FileInfo, err error) error { if err != nil && !os.IsNotExist(err) { - return err + return errors.WithStack(err) } if os.IsNotExist(err) { return nil @@ -191,7 +191,7 @@ func (s *PosixStorage) List(prefix, startWith, delimiter string, doneCh <-chan s p, err = filepath.Rel(s.dataDir, p) if err != nil { - return err + return errors.WithStack(err) } if !recursive && len(p) > len(prefix) { rel := strings.TrimPrefix(p, prefix) diff --git a/internal/objectstorage/posixflat.go b/internal/objectstorage/posixflat.go index 1a4de39..343d377 100644 --- a/internal/objectstorage/posixflat.go +++ b/internal/objectstorage/posixflat.go @@ -23,7 +23,7 @@ import ( "strings" "unicode/utf8" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/errors" ) const ( @@ -207,15 +207,15 @@ type PosixFlatStorage struct { func NewPosixFlat(baseDir string) (*PosixFlatStorage, error) { if err := os.MkdirAll(baseDir, 0770); err != nil { - return nil, err + return nil, errors.WithStack(err) } dataDir := filepath.Join(baseDir, dataDirName) tmpDir := filepath.Join(baseDir, tmpDirName) if err := os.MkdirAll(dataDir, 0770); err != nil { - return nil, errors.Errorf("failed to create data dir: %w", err) + return nil, errors.Wrapf(err, "failed to create data dir") } if err := os.MkdirAll(tmpDir, 0770); err != nil { - return nil, errors.Errorf("failed to create tmp dir: %w", err) + return nil, errors.Wrapf(err, "failed to create tmp dir") } return &PosixFlatStorage{ dataDir: dataDir, @@ -233,7 +233,7 @@ func (s *PosixFlatStorage) fsPath(p string) (string, error) { func (s *PosixFlatStorage) Stat(p string) (*ObjectInfo, error) { fspath, err := s.fsPath(p) if err != nil { - return nil, err + return nil, errors.WithStack(err) } fi, err := os.Stat(fspath) @@ -241,7 +241,7 @@ func (s *PosixFlatStorage) Stat(p string) (*ObjectInfo, error) { if os.IsNotExist(err) { return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) } - return nil, err + return nil, errors.WithStack(err) } return &ObjectInfo{Path: p, LastModified: fi.ModTime(), Size: fi.Size()}, nil @@ -250,24 +250,24 @@ func (s *PosixFlatStorage) Stat(p string) (*ObjectInfo, error) { func (s *PosixFlatStorage) ReadObject(p string) (ReadSeekCloser, error) { fspath, err := s.fsPath(p) if err != nil { - return nil, err + return nil, errors.WithStack(err) } f, err := os.Open(fspath) if err != nil && os.IsNotExist(err) { return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) } - return f, err + return f, errors.WithStack(err) } func (s *PosixFlatStorage) WriteObject(p string, data io.Reader, size int64, persist bool) error { fspath, err := s.fsPath(p) if err != nil { - return err + return errors.WithStack(err) } if err := os.MkdirAll(path.Dir(fspath), 0770); err != nil { - return err + return errors.WithStack(err) } r := data @@ -276,21 +276,21 @@ func (s *PosixFlatStorage) WriteObject(p string, data io.Reader, size int64, per } return writeFileAtomicFunc(fspath, s.dataDir, s.tmpDir, 0660, persist, func(f io.Writer) error { _, err := io.Copy(f, r) - return err + return errors.WithStack(err) }) } func (s *PosixFlatStorage) DeleteObject(p string) error { fspath, err := s.fsPath(p) if err != nil { - return err + return errors.WithStack(err) } if err := os.Remove(fspath); err != nil { if os.IsNotExist(err) { return NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) } - return err + return errors.WithStack(err) } // try to remove parent empty dirs @@ -354,7 +354,7 @@ func (s *PosixFlatStorage) List(prefix, startWith, delimiter string, doneCh <-ch defer close(objectCh) err := filepath.Walk(root, func(ep string, info os.FileInfo, err error) error { if err != nil && !os.IsNotExist(err) { - return err + return errors.WithStack(err) } if os.IsNotExist(err) { return nil @@ -366,11 +366,11 @@ func (s *PosixFlatStorage) List(prefix, startWith, delimiter string, doneCh <-ch p, err = filepath.Rel(s.dataDir, p) if err != nil { - return err + return errors.WithStack(err) } p, _, err = unescape(p) if err != nil { - return err + return errors.WithStack(err) } if !recursive && len(p) > len(prefix) { rel := strings.TrimPrefix(p, prefix) @@ -390,7 +390,7 @@ func (s *PosixFlatStorage) List(prefix, startWith, delimiter string, doneCh <-ch hasFile := true _, err = os.Stat(ep + ".f") if err != nil && !os.IsNotExist(err) { - return err + return errors.WithStack(err) } if os.IsNotExist(err) { hasFile = false diff --git a/internal/objectstorage/posixflat_test.go b/internal/objectstorage/posixflat_test.go index a9cca81..3204b88 100644 --- a/internal/objectstorage/posixflat_test.go +++ b/internal/objectstorage/posixflat_test.go @@ -21,7 +21,7 @@ import ( "path/filepath" "testing" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/errors" ) func TestEscapeUnescape(t *testing.T) { diff --git a/internal/objectstorage/s3.go b/internal/objectstorage/s3.go index 61876ad..a947c1d 100644 --- a/internal/objectstorage/s3.go +++ b/internal/objectstorage/s3.go @@ -21,8 +21,8 @@ import ( "os" "strings" + "agola.io/agola/internal/errors" minio "github.com/minio/minio-go/v6" - errors "golang.org/x/xerrors" ) type S3Storage struct { @@ -35,21 +35,21 @@ type S3Storage struct { func NewS3(bucket, location, endpoint, accessKeyID, secretAccessKey string, secure bool) (*S3Storage, error) { minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, secure) if err != nil { - return nil, err + return nil, errors.WithStack(err) } minioCore, err := minio.NewCore(endpoint, accessKeyID, secretAccessKey, secure) if err != nil { - return nil, err + return nil, errors.WithStack(err) } exists, err := minioClient.BucketExists(bucket) if err != nil { - return nil, errors.Errorf("cannot check if bucket %q in location %q exits: %w", bucket, location, err) + return nil, errors.Wrapf(err, "cannot check if bucket %q in location %q exits", bucket, location) } if !exists { if err := minioClient.MakeBucket(bucket, location); err != nil { - return nil, errors.Errorf("cannot create bucket %q in location %q: %w", bucket, location, err) + return nil, errors.Wrapf(err, "cannot create bucket %q in location %q", bucket, location) } } @@ -67,7 +67,7 @@ func (s *S3Storage) Stat(p string) (*ObjectInfo, error) { if merr.StatusCode == http.StatusNotFound { return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) } - return nil, merr + return nil, errors.WithStack(merr) } return &ObjectInfo{Path: p, LastModified: oi.LastModified, Size: oi.Size}, nil @@ -79,9 +79,12 @@ func (s *S3Storage) ReadObject(filepath string) (ReadSeekCloser, error) { if merr.StatusCode == http.StatusNotFound { return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", filepath)) } - return nil, merr + return nil, errors.WithStack(merr) } - return s.minioClient.GetObject(s.bucket, filepath, minio.GetObjectOptions{}) + + o, err := s.minioClient.GetObject(s.bucket, filepath, minio.GetObjectOptions{}) + + return o, errors.WithStack(err) } func (s *S3Storage) WriteObject(filepath string, data io.Reader, size int64, persist bool) error { @@ -92,30 +95,30 @@ func (s *S3Storage) WriteObject(filepath string, data io.Reader, size int64, per if size >= 0 { lr := io.LimitReader(data, size) _, err := s.minioClient.PutObject(s.bucket, filepath, lr, size, minio.PutObjectOptions{ContentType: "application/octet-stream"}) - return err + return errors.WithStack(err) } // hack to know the real file size or minio will do this in memory with big memory usage since s3 doesn't support real streaming of unknown sizes // TODO(sgotti) wait for minio client to expose an api to provide the max object size so we can remove this tmpfile, err := ioutil.TempFile(os.TempDir(), "s3") if err != nil { - return err + return errors.WithStack(err) } defer tmpfile.Close() defer os.Remove(tmpfile.Name()) size, err = io.Copy(tmpfile, data) if err != nil { - return err + return errors.WithStack(err) } if _, err := tmpfile.Seek(0, 0); err != nil { - return err + return errors.WithStack(err) } _, err = s.minioClient.PutObject(s.bucket, filepath, tmpfile, size, minio.PutObjectOptions{ContentType: "application/octet-stream"}) - return err + return errors.WithStack(err) } func (s *S3Storage) DeleteObject(filepath string) error { - return s.minioClient.RemoveObject(s.bucket, filepath) + return errors.WithStack(s.minioClient.RemoveObject(s.bucket, filepath)) } func (s *S3Storage) List(prefix, startWith, delimiter string, doneCh <-chan struct{}) <-chan ObjectInfo { diff --git a/internal/runconfig/runconfig.go b/internal/runconfig/runconfig.go index 7994e8a..86440c4 100644 --- a/internal/runconfig/runconfig.go +++ b/internal/runconfig/runconfig.go @@ -19,12 +19,11 @@ import ( "strings" "agola.io/agola/internal/config" + "agola.io/agola/internal/errors" itypes "agola.io/agola/internal/services/types" "agola.io/agola/internal/util" rstypes "agola.io/agola/services/runservice/types" "agola.io/agola/services/types" - - errors "golang.org/x/xerrors" ) const ( @@ -192,7 +191,7 @@ fi return rws default: - panic(fmt.Errorf("unknown config step type: %s", util.Dump(cs))) + panic(errors.Errorf("unknown config step type: %s", util.Dump(cs))) } } @@ -461,7 +460,7 @@ func genValue(val config.Value, variables map[string]string) string { case config.ValueTypeFromVariable: return variables[val.Value] default: - panic(fmt.Errorf("wrong value type: %q", val.Value)) + panic(errors.Errorf("wrong value type: %q", val.Value)) } } diff --git a/internal/runconfig/runconfig_test.go b/internal/runconfig/runconfig_test.go index baff22b..b54a320 100644 --- a/internal/runconfig/runconfig_test.go +++ b/internal/runconfig/runconfig_test.go @@ -20,13 +20,13 @@ import ( "testing" "agola.io/agola/internal/config" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" rstypes "agola.io/agola/services/runservice/types" "agola.io/agola/services/types" "k8s.io/apimachinery/pkg/api/resource" "github.com/google/go-cmp/cmp" - errors "golang.org/x/xerrors" ) var uuid = &util.TestUUIDGenerator{} @@ -128,7 +128,7 @@ func TestGenTasksLevels(t *testing.T) { }, }, }, - err: fmt.Errorf("circular dependency detected"), + err: errors.Errorf("circular dependency detected"), }, { name: "Test circular dependency between 3 tasks: a -> b -> c -> a", @@ -155,7 +155,7 @@ func TestGenTasksLevels(t *testing.T) { }, }, }, - err: fmt.Errorf("circular dependency detected"), + err: errors.Errorf("circular dependency detected"), }, { name: "Test circular dependency between 3 tasks: a -> b -> c -> b", @@ -182,7 +182,7 @@ func TestGenTasksLevels(t *testing.T) { }, }, }, - err: fmt.Errorf("circular dependency detected"), + err: errors.Errorf("circular dependency detected"), }, } for _, tt := range tests { diff --git a/internal/sequence/sequence.go b/internal/sequence/sequence.go index 10e2896..accb32f 100644 --- a/internal/sequence/sequence.go +++ b/internal/sequence/sequence.go @@ -23,8 +23,8 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" - errors "golang.org/x/xerrors" ) type Sequence struct { @@ -55,11 +55,11 @@ func Parse(s string) (*Sequence, error) { } epoch, err := strconv.ParseUint(parts[0], 32, 64) if err != nil { - return nil, errors.Errorf("cannot parse sequence epoch %q: %w", epoch, err) + return nil, errors.Wrapf(err, "cannot parse sequence epoch %q", epoch) } c, err := strconv.ParseUint(parts[1], 32, 64) if err != nil { - return nil, errors.Errorf("cannot parse sequence count %q: %w", c, err) + return nil, errors.Wrapf(err, "cannot parse sequence count %q", c) } return &Sequence{ Epoch: epoch, @@ -74,7 +74,7 @@ func (s *Sequence) EqualEpoch(s2 *Sequence) bool { func CurSequence(ctx context.Context, e *etcd.Store, key string) (*Sequence, bool, error) { resp, err := e.Get(ctx, key, 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return nil, false, err + return nil, false, errors.WithStack(err) } if errors.Is(err, etcd.ErrKeyNotFound) { return nil, false, nil @@ -84,7 +84,7 @@ func CurSequence(ctx context.Context, e *etcd.Store, key string) (*Sequence, boo if !errors.Is(err, etcd.ErrKeyNotFound) { kv := resp.Kvs[0] if err := json.Unmarshal(kv.Value, &seq); err != nil { - return nil, false, err + return nil, false, errors.WithStack(err) } } return seq, true, nil @@ -93,7 +93,7 @@ func CurSequence(ctx context.Context, e *etcd.Store, key string) (*Sequence, boo func IncSequence(ctx context.Context, e *etcd.Store, key string) (*Sequence, error) { resp, err := e.Get(ctx, key, 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return nil, err + return nil, errors.WithStack(err) } var revision int64 @@ -101,7 +101,7 @@ func IncSequence(ctx context.Context, e *etcd.Store, key string) (*Sequence, err if !errors.Is(err, etcd.ErrKeyNotFound) { kv := resp.Kvs[0] if err := json.Unmarshal(kv.Value, &seq); err != nil { - return nil, err + return nil, errors.WithStack(err) } revision = kv.ModRevision } @@ -120,12 +120,12 @@ func IncSequence(ctx context.Context, e *etcd.Store, key string) (*Sequence, err seqj, err := json.Marshal(seq) if err != nil { - return nil, err + return nil, errors.WithStack(err) } _, err = e.AtomicPut(ctx, key, seqj, revision, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return seq, nil diff --git a/internal/sequence/sequence_test.go b/internal/sequence/sequence_test.go index 97623e2..1c9b591 100644 --- a/internal/sequence/sequence_test.go +++ b/internal/sequence/sequence_test.go @@ -15,10 +15,11 @@ package sequence import ( - "errors" "math" "testing" + "agola.io/agola/internal/errors" + "github.com/google/go-cmp/cmp" ) diff --git a/internal/services/common/gitsource.go b/internal/services/common/gitsource.go index 298c6d5..43c26f7 100644 --- a/internal/services/common/gitsource.go +++ b/internal/services/common/gitsource.go @@ -15,43 +15,48 @@ package common import ( + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" "agola.io/agola/internal/gitsources/gitea" "agola.io/agola/internal/gitsources/github" "agola.io/agola/internal/gitsources/gitlab" cstypes "agola.io/agola/services/configstore/types" - - errors "golang.org/x/xerrors" ) func newGitea(rs *cstypes.RemoteSource, accessToken string) (*gitea.Client, error) { - return gitea.New(gitea.Opts{ + c, err := gitea.New(gitea.Opts{ APIURL: rs.APIURL, SkipVerify: rs.SkipVerify, Token: accessToken, Oauth2ClientID: rs.Oauth2ClientID, Oauth2Secret: rs.Oauth2ClientSecret, }) + + return c, errors.WithStack(err) } func newGitlab(rs *cstypes.RemoteSource, accessToken string) (*gitlab.Client, error) { - return gitlab.New(gitlab.Opts{ + c, err := gitlab.New(gitlab.Opts{ APIURL: rs.APIURL, SkipVerify: rs.SkipVerify, Token: accessToken, Oauth2ClientID: rs.Oauth2ClientID, Oauth2Secret: rs.Oauth2ClientSecret, }) + + return c, errors.WithStack(err) } func newGithub(rs *cstypes.RemoteSource, accessToken string) (*github.Client, error) { - return github.New(github.Opts{ + c, err := github.New(github.Opts{ APIURL: rs.APIURL, SkipVerify: rs.SkipVerify, Token: accessToken, Oauth2ClientID: rs.Oauth2ClientID, Oauth2Secret: rs.Oauth2ClientSecret, }) + + return c, errors.WithStack(err) } func GetAccessToken(rs *cstypes.RemoteSource, userAccessToken, oauth2AccessToken string) (string, error) { @@ -71,7 +76,7 @@ func GetGitSource(rs *cstypes.RemoteSource, la *cstypes.LinkedAccount) (gitsourc var err error accessToken, err = GetAccessToken(rs, la.UserAccessToken, la.Oauth2AccessToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } } @@ -88,7 +93,7 @@ func GetGitSource(rs *cstypes.RemoteSource, la *cstypes.LinkedAccount) (gitsourc return nil, errors.Errorf("remote source %s isn't a valid git source", rs.Name) } - return gitSource, err + return gitSource, errors.WithStack(err) } func GetUserSource(rs *cstypes.RemoteSource, accessToken string) (gitsource.UserSource, error) { @@ -103,7 +108,7 @@ func GetUserSource(rs *cstypes.RemoteSource, accessToken string) (gitsource.User return nil, errors.Errorf("unknown remote source auth type") } - return userSource, err + return userSource, errors.WithStack(err) } func GetOauth2Source(rs *cstypes.RemoteSource, accessToken string) (gitsource.Oauth2Source, error) { @@ -120,7 +125,7 @@ func GetOauth2Source(rs *cstypes.RemoteSource, accessToken string) (gitsource.Oa return nil, errors.Errorf("remote source %s isn't a valid oauth2 source", rs.Name) } - return oauth2Source, err + return oauth2Source, errors.WithStack(err) } func GetPasswordSource(rs *cstypes.RemoteSource, accessToken string) (gitsource.PasswordSource, error) { @@ -133,5 +138,5 @@ func GetPasswordSource(rs *cstypes.RemoteSource, accessToken string) (gitsource. return nil, errors.Errorf("remote source %s isn't a valid oauth2 source", rs.Name) } - return passwordSource, err + return passwordSource, errors.WithStack(err) } diff --git a/internal/services/common/jwt.go b/internal/services/common/jwt.go index 2f538a5..4dede3c 100644 --- a/internal/services/common/jwt.go +++ b/internal/services/common/jwt.go @@ -19,8 +19,8 @@ import ( "encoding/json" "time" + "agola.io/agola/internal/errors" "github.com/golang-jwt/jwt/v4" - errors "golang.org/x/xerrors" ) type TokenSigningData struct { @@ -44,13 +44,14 @@ func GenerateGenericJWTToken(sd *TokenSigningData, claims jwt.Claims) (string, e return "", errors.Errorf("unsupported signing method %q", sd.Method.Alg()) } // Sign and get the complete encoded token as a string - return token.SignedString(key) + ts, err := token.SignedString(key) + return ts, errors.WithStack(err) } func GenerateOauth2JWTToken(sd *TokenSigningData, remoteSourceName, requestType string, request interface{}) (string, error) { requestj, err := json.Marshal(request) if err != nil { - return "", err + return "", errors.WithStack(err) } return GenerateGenericJWTToken(sd, jwt.MapClaims{ diff --git a/internal/services/common/run.go b/internal/services/common/run.go index d81ba72..7e1ac36 100644 --- a/internal/services/common/run.go +++ b/internal/services/common/run.go @@ -15,13 +15,12 @@ package common import ( - "fmt" "net/url" "path" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/types" "agola.io/agola/internal/util" - errors "golang.org/x/xerrors" ) type GroupType string @@ -49,7 +48,7 @@ func WebHookEventToRunRefType(we types.WebhookEvent) types.RunRefType { return types.RunRefTypePullRequest } - panic(fmt.Errorf("invalid webhook event type: %q", we)) + panic(errors.Errorf("invalid webhook event type: %q", we)) } func GenRunGroup(baseGroupType GroupType, baseGroupID string, groupType GroupType, group string) string { diff --git a/internal/services/config/config.go b/internal/services/config/config.go index 0a11e3f..108ae4d 100644 --- a/internal/services/config/config.go +++ b/internal/services/config/config.go @@ -18,9 +18,9 @@ import ( "io/ioutil" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" - errors "golang.org/x/xerrors" yaml "gopkg.in/yaml.v2" ) @@ -273,12 +273,12 @@ var defaultConfig = Config{ func Parse(configFile string, componentsNames []string) (*Config, error) { configData, err := ioutil.ReadFile(configFile) if err != nil { - return nil, err + return nil, errors.WithStack(err) } c := &defaultConfig if err := yaml.Unmarshal(configData, &c); err != nil { - return nil, err + return nil, errors.WithStack(err) } return c, Validate(c, componentsNames) @@ -333,7 +333,7 @@ func Validate(c *Config, componentsNames []string) error { return errors.Errorf("gateway runserviceURL is empty") } if err := validateWeb(&c.Gateway.Web); err != nil { - return errors.Errorf("gateway web configuration error: %w", err) + return errors.Wrapf(err, "gateway web configuration error") } } @@ -343,7 +343,7 @@ func Validate(c *Config, componentsNames []string) error { return errors.Errorf("configstore dataDir is empty") } if err := validateWeb(&c.Configstore.Web); err != nil { - return errors.Errorf("configstore web configuration error: %w", err) + return errors.Wrapf(err, "configstore web configuration error") } } @@ -353,7 +353,7 @@ func Validate(c *Config, componentsNames []string) error { return errors.Errorf("runservice dataDir is empty") } if err := validateWeb(&c.Runservice.Web); err != nil { - return errors.Errorf("runservice web configuration error: %w", err) + return errors.Wrapf(err, "runservice web configuration error") } } @@ -379,7 +379,7 @@ func Validate(c *Config, componentsNames []string) error { } if err := validateInitImage(&c.Executor.InitImage); err != nil { - return errors.Errorf("executor initImage configuration error: %w", err) + return errors.Wrapf(err, "executor initImage configuration error") } } diff --git a/internal/services/config/config_test.go b/internal/services/config/config_test.go index 9b8b9aa..5066563 100644 --- a/internal/services/config/config_test.go +++ b/internal/services/config/config_test.go @@ -20,7 +20,7 @@ import ( "path" "testing" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/errors" ) func TestParseConfig(t *testing.T) { diff --git a/internal/services/configstore/action/action.go b/internal/services/configstore/action/action.go index 03c3b2d..5994c62 100644 --- a/internal/services/configstore/action/action.go +++ b/internal/services/configstore/action/action.go @@ -17,13 +17,13 @@ package action import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) type ActionHandler struct { @@ -53,7 +53,7 @@ func (h *ActionHandler) ResolveConfigID(tx *db.Tx, configType types.ConfigType, case types.ConfigTypeProjectGroup: group, err := h.readDB.GetProjectGroup(tx, ref) if err != nil { - return "", err + return "", errors.WithStack(err) } if group == nil { return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("group with ref %q doesn't exists", ref)) @@ -63,7 +63,7 @@ func (h *ActionHandler) ResolveConfigID(tx *db.Tx, configType types.ConfigType, case types.ConfigTypeProject: project, err := h.readDB.GetProject(tx, ref) if err != nil { - return "", err + return "", errors.WithStack(err) } if project == nil { return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with ref %q doesn't exists", ref)) diff --git a/internal/services/configstore/action/maintenance.go b/internal/services/configstore/action/maintenance.go index bb66996..f36a4a9 100644 --- a/internal/services/configstore/action/maintenance.go +++ b/internal/services/configstore/action/maintenance.go @@ -18,17 +18,16 @@ import ( "context" "io" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/services/configstore/common" "agola.io/agola/internal/util" - - errors "golang.org/x/xerrors" ) func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error { resp, err := h.e.Get(ctx, common.EtcdMaintenanceKey, 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if enable && len(resp.Kvs) > 0 { @@ -41,7 +40,7 @@ func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error if enable { txResp, err := h.e.AtomicPut(ctx, common.EtcdMaintenanceKey, []byte{}, 0, nil) if err != nil { - return err + return errors.WithStack(err) } if !txResp.Succeeded { return errors.Errorf("failed to create maintenance mode key due to concurrent update") @@ -51,7 +50,7 @@ func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error if !enable { txResp, err := h.e.AtomicDelete(ctx, common.EtcdMaintenanceKey, resp.Kvs[0].ModRevision) if err != nil { - return err + return errors.WithStack(err) } if !txResp.Succeeded { return errors.Errorf("failed to delete maintenance mode key due to concurrent update") @@ -62,12 +61,12 @@ func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error } func (h *ActionHandler) Export(ctx context.Context, w io.Writer) error { - return h.dm.Export(ctx, w) + return errors.WithStack(h.dm.Export(ctx, w)) } func (h *ActionHandler) Import(ctx context.Context, r io.Reader) error { if !h.maintenanceMode { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("not in maintenance mode")) } - return h.dm.Import(ctx, r) + return errors.WithStack(h.dm.Import(ctx, r)) } diff --git a/internal/services/configstore/action/org.go b/internal/services/configstore/action/org.go index fdf290d..4bf9f4d 100644 --- a/internal/services/configstore/action/org.go +++ b/internal/services/configstore/action/org.go @@ -22,12 +22,13 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" "github.com/gofrs/uuid" - errors "golang.org/x/xerrors" ) type OrgMemberResponse struct { @@ -48,17 +49,17 @@ func (h *ActionHandler) GetOrgMembers(ctx context.Context, orgRef string) ([]*Or var err error org, err := h.readDB.GetOrg(tx, orgRef) if err != nil { - return err + return errors.WithStack(err) } if org == nil { return util.NewAPIError(util.ErrNotExist, errors.Errorf("org %q doesn't exist", orgRef)) } orgUsers, err = h.readDB.GetOrgUsers(tx, org.ID) - return err + return errors.WithStack(err) }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } res := make([]*OrgMemberResponse, len(orgUsers)) @@ -89,13 +90,13 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) var err error cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } // check duplicate org name o, err := h.readDB.GetOrgByName(tx, org.Name) if err != nil { - return err + return errors.WithStack(err) } if o != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q already exists", o.Name)) @@ -104,7 +105,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) if org.CreatorUserID != "" { user, err := h.readDB.GetUser(tx, org.CreatorUserID) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("creator user %q doesn't exist", org.CreatorUserID)) @@ -114,7 +115,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } actions := []*datamanager.Action{} @@ -123,7 +124,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) org.CreatedAt = time.Now() orgj, err := json.Marshal(org) if err != nil { - return nil, errors.Errorf("failed to marshal org: %w", err) + return nil, errors.Wrapf(err, "failed to marshal org") } actions = append(actions, &datamanager.Action{ ActionType: datamanager.ActionTypePut, @@ -142,7 +143,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) } orgmemberj, err := json.Marshal(orgmember) if err != nil { - return nil, errors.Errorf("failed to marshal project group: %w", err) + return nil, errors.Wrapf(err, "failed to marshal project group") } actions = append(actions, &datamanager.Action{ ActionType: datamanager.ActionTypePut, @@ -164,7 +165,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) } pgj, err := json.Marshal(pg) if err != nil { - return nil, errors.Errorf("failed to marshal project group: %w", err) + return nil, errors.Wrapf(err, "failed to marshal project group") } actions = append(actions, &datamanager.Action{ ActionType: datamanager.ActionTypePut, @@ -174,7 +175,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) }) _, err = h.dm.WriteWal(ctx, actions, cgt) - return org, err + return org, errors.WithStack(err) } func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { @@ -187,7 +188,7 @@ func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { // check org existance org, err = h.readDB.GetOrgByName(tx, orgRef) if err != nil { - return err + return errors.WithStack(err) } if org == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q doesn't exist", orgRef)) @@ -197,13 +198,13 @@ func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { cgNames := []string{util.EncodeSha256Hex("orgid-" + org.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } // TODO(sgotti) delete all project groups, projects etc... @@ -216,7 +217,7 @@ func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { } _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } // AddOrgMember add/updates an org member. @@ -237,7 +238,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string // check existing org org, err = h.readDB.GetOrg(tx, orgRef) if err != nil { - return err + return errors.WithStack(err) } if org == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q doesn't exists", orgRef)) @@ -245,7 +246,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string // check existing user user, err = h.readDB.GetUser(tx, userRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exists", userRef)) @@ -254,19 +255,19 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string // fetch org member if it already exist orgmember, err = h.readDB.GetOrgMemberByOrgUserID(tx, org.ID, user.ID) if err != nil { - return err + return errors.WithStack(err) } cgNames := []string{util.EncodeSha256Hex(fmt.Sprintf("orgmember-%s-%s", org.ID, user.ID))} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // update if role changed @@ -287,7 +288,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string actions := []*datamanager.Action{} orgmemberj, err := json.Marshal(orgmember) if err != nil { - return nil, errors.Errorf("failed to marshal project group: %w", err) + return nil, errors.Wrapf(err, "failed to marshal project group") } actions = append(actions, &datamanager.Action{ ActionType: datamanager.ActionTypePut, @@ -297,7 +298,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string }) _, err = h.dm.WriteWal(ctx, actions, cgt) - return orgmember, err + return orgmember, errors.WithStack(err) } // RemoveOrgMember removes an org member. @@ -313,7 +314,7 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str // check existing org org, err = h.readDB.GetOrg(tx, orgRef) if err != nil { - return err + return errors.WithStack(err) } if org == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q doesn't exists", orgRef)) @@ -321,7 +322,7 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str // check existing user user, err = h.readDB.GetUser(tx, userRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exists", userRef)) @@ -330,7 +331,7 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str // check that org member exists orgmember, err = h.readDB.GetOrgMemberByOrgUserID(tx, org.ID, user.ID) if err != nil { - return err + return errors.WithStack(err) } if orgmember == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("orgmember for org %q, user %q doesn't exists", orgRef, userRef)) @@ -339,13 +340,13 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str cgNames := []string{util.EncodeSha256Hex(fmt.Sprintf("orgmember-%s-%s", org.ID, user.ID))} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } actions := []*datamanager.Action{} @@ -356,5 +357,5 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str }) _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } diff --git a/internal/services/configstore/action/project.go b/internal/services/configstore/action/project.go index d569703..5121987 100644 --- a/internal/services/configstore/action/project.go +++ b/internal/services/configstore/action/project.go @@ -21,11 +21,12 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" "github.com/gofrs/uuid" - errors "golang.org/x/xerrors" ) func (h *ActionHandler) ValidateProject(ctx context.Context, project *types.Project) error { @@ -69,10 +70,10 @@ func (h *ActionHandler) GetProject(ctx context.Context, projectRef string) (*typ err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error project, err = h.readDB.GetProject(tx, projectRef) - return err + return errors.WithStack(err) }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if project == nil { @@ -84,7 +85,7 @@ func (h *ActionHandler) GetProject(ctx context.Context, projectRef string) (*typ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Project) (*types.Project, error) { if err := h.ValidateProject(ctx, project); err != nil { - return nil, err + return nil, errors.WithStack(err) } var cgt *datamanager.ChangeGroupsUpdateToken @@ -94,7 +95,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec var err error group, err := h.readDB.GetProjectGroup(tx, project.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } if group == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", project.Parent.ID)) @@ -103,7 +104,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec groupPath, err := h.readDB.GetProjectGroupPath(tx, group) if err != nil { - return err + return errors.WithStack(err) } pp := path.Join(groupPath, project.Name) @@ -112,13 +113,13 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec cgNames := []string{util.EncodeSha256Hex("projectpath-" + pp)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } // check duplicate project name p, err := h.readDB.GetProjectByName(tx, project.Parent.ID, project.Name) if err != nil { - return err + return errors.WithStack(err) } if p != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with name %q, path %q already exists", p.Name, pp)) @@ -128,7 +129,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec // check that the linked account matches the remote source user, err := h.readDB.GetUserByLinkedAccount(tx, project.LinkedAccountID) if err != nil { - return errors.Errorf("failed to get user with linked account id %q: %w", project.LinkedAccountID, err) + return errors.Wrapf(err, "failed to get user with linked account id %q", project.LinkedAccountID) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for linked account %q doesn't exist", project.LinkedAccountID)) @@ -145,7 +146,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } project.ID = uuid.Must(uuid.NewV4()).String() @@ -156,7 +157,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec pcj, err := json.Marshal(project) if err != nil { - return nil, errors.Errorf("failed to marshal project: %w", err) + return nil, errors.Wrapf(err, "failed to marshal project") } actions := []*datamanager.Action{ { @@ -168,7 +169,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec } _, err = h.dm.WriteWal(ctx, actions, cgt) - return project, err + return project, errors.WithStack(err) } type UpdateProjectRequest struct { @@ -179,7 +180,7 @@ type UpdateProjectRequest struct { func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectRequest) (*types.Project, error) { if err := h.ValidateProject(ctx, req.Project); err != nil { - return nil, err + return nil, errors.WithStack(err) } var cgt *datamanager.ChangeGroupsUpdateToken @@ -190,7 +191,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq // check project exists p, err := h.readDB.GetProject(tx, req.ProjectRef) if err != nil { - return err + return errors.WithStack(err) } if p == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with ref %q doesn't exist", req.ProjectRef)) @@ -203,7 +204,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq // check parent project group exists group, err := h.readDB.GetProjectGroup(tx, req.Project.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } if group == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", req.Project.Parent.ID)) @@ -212,7 +213,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq groupPath, err := h.readDB.GetProjectGroupPath(tx, group) if err != nil { - return err + return errors.WithStack(err) } pp := path.Join(groupPath, req.Project.Name) @@ -220,7 +221,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq // check duplicate project name ap, err := h.readDB.GetProjectByName(tx, req.Project.Parent.ID, req.Project.Name) if err != nil { - return err + return errors.WithStack(err) } if ap != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with name %q, path %q already exists", req.Project.Name, pp)) @@ -236,14 +237,14 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq // get old parent project group curGroup, err := h.readDB.GetProjectGroup(tx, p.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } if curGroup == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", p.Parent.ID)) } curGroupPath, err := h.readDB.GetProjectGroupPath(tx, curGroup) if err != nil { - return err + return errors.WithStack(err) } pp := path.Join(curGroupPath, req.Project.Name) @@ -252,14 +253,14 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } if req.Project.RemoteRepositoryConfigType == types.RemoteRepositoryConfigTypeRemoteSource { // check that the linked account matches the remote source user, err := h.readDB.GetUserByLinkedAccount(tx, req.Project.LinkedAccountID) if err != nil { - return errors.Errorf("failed to get user with linked account id %q: %w", req.Project.LinkedAccountID, err) + return errors.Wrapf(err, "failed to get user with linked account id %q", req.Project.LinkedAccountID) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for linked account %q doesn't exist", req.Project.LinkedAccountID)) @@ -276,12 +277,12 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } pcj, err := json.Marshal(req.Project) if err != nil { - return nil, errors.Errorf("failed to marshal project: %w", err) + return nil, errors.Wrapf(err, "failed to marshal project") } actions := []*datamanager.Action{ { @@ -293,7 +294,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq } _, err = h.dm.WriteWal(ctx, actions, cgt) - return req.Project, err + return req.Project, errors.WithStack(err) } func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) error { @@ -308,7 +309,7 @@ func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) er // check project existance project, err = h.readDB.GetProject(tx, projectRef) if err != nil { - return err + return errors.WithStack(err) } if project == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project %q doesn't exist", projectRef)) @@ -318,13 +319,13 @@ func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) er cgNames := []string{util.EncodeSha256Hex(project.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } // TODO(sgotti) implement childs garbage collection @@ -337,5 +338,5 @@ func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) er } _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } diff --git a/internal/services/configstore/action/projectgroup.go b/internal/services/configstore/action/projectgroup.go index 14a919a..49055d3 100644 --- a/internal/services/configstore/action/projectgroup.go +++ b/internal/services/configstore/action/projectgroup.go @@ -22,11 +22,12 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" "github.com/gofrs/uuid" - errors "golang.org/x/xerrors" ) func (h *ActionHandler) GetProjectGroup(ctx context.Context, projectGroupRef string) (*types.ProjectGroup, error) { @@ -34,10 +35,10 @@ func (h *ActionHandler) GetProjectGroup(ctx context.Context, projectGroupRef str err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error projectGroup, err = h.readDB.GetProjectGroup(tx, projectGroupRef) - return err + return errors.WithStack(err) }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if projectGroup == nil { @@ -53,7 +54,7 @@ func (h *ActionHandler) GetProjectGroupSubgroups(ctx context.Context, projectGro var err error projectGroup, err := h.readDB.GetProjectGroup(tx, projectGroupRef) if err != nil { - return err + return errors.WithStack(err) } if projectGroup == nil { @@ -61,10 +62,10 @@ func (h *ActionHandler) GetProjectGroupSubgroups(ctx context.Context, projectGro } projectGroups, err = h.readDB.GetProjectGroupSubgroups(tx, projectGroup.ID) - return err + return errors.WithStack(err) }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return projectGroups, nil @@ -76,7 +77,7 @@ func (h *ActionHandler) GetProjectGroupProjects(ctx context.Context, projectGrou var err error projectGroup, err := h.readDB.GetProjectGroup(tx, projectGroupRef) if err != nil { - return err + return errors.WithStack(err) } if projectGroup == nil { @@ -84,10 +85,10 @@ func (h *ActionHandler) GetProjectGroupProjects(ctx context.Context, projectGrou } projects, err = h.readDB.GetProjectGroupProjects(tx, projectGroup.ID) - return err + return errors.WithStack(err) }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return projects, nil } @@ -125,7 +126,7 @@ func (h *ActionHandler) ValidateProjectGroup(ctx context.Context, projectGroup * func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *types.ProjectGroup) (*types.ProjectGroup, error) { if err := h.ValidateProjectGroup(ctx, projectGroup); err != nil { - return nil, err + return nil, errors.WithStack(err) } if projectGroup.Parent.Type != types.ConfigTypeProjectGroup { @@ -138,7 +139,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty err := h.readDB.Do(ctx, func(tx *db.Tx) error { parentProjectGroup, err := h.readDB.GetProjectGroup(tx, projectGroup.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } if parentProjectGroup == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", projectGroup.Parent.ID)) @@ -150,7 +151,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty groupPath, err := h.readDB.GetProjectGroupPath(tx, parentProjectGroup) if err != nil { - return err + return errors.WithStack(err) } pp := path.Join(groupPath, projectGroup.Name) @@ -159,13 +160,13 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty cgNames := []string{util.EncodeSha256Hex("projectpath-" + pp)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } // check duplicate project group name pg, err := h.readDB.GetProjectGroupByName(tx, projectGroup.Parent.ID, projectGroup.Name) if err != nil { - return err + return errors.WithStack(err) } if pg != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with name %q, path %q already exists", pg.Name, pp)) @@ -173,7 +174,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } projectGroup.ID = uuid.Must(uuid.NewV4()).String() @@ -181,7 +182,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty pgj, err := json.Marshal(projectGroup) if err != nil { - return nil, errors.Errorf("failed to marshal projectGroup: %w", err) + return nil, errors.Wrapf(err, "failed to marshal projectGroup") } actions := []*datamanager.Action{ { @@ -193,7 +194,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty } _, err = h.dm.WriteWal(ctx, actions, cgt) - return projectGroup, err + return projectGroup, errors.WithStack(err) } type UpdateProjectGroupRequest struct { @@ -204,7 +205,7 @@ type UpdateProjectGroupRequest struct { func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProjectGroupRequest) (*types.ProjectGroup, error) { if err := h.ValidateProjectGroup(ctx, req.ProjectGroup); err != nil { - return nil, err + return nil, errors.WithStack(err) } var cgt *datamanager.ChangeGroupsUpdateToken @@ -215,7 +216,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje // check project exists pg, err := h.readDB.GetProjectGroup(tx, req.ProjectGroupRef) if err != nil { - return err + return errors.WithStack(err) } if pg == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with ref %q doesn't exist", req.ProjectGroupRef)) @@ -244,7 +245,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje // check parent exists group, err := h.readDB.GetProjectGroup(tx, req.ProjectGroup.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } if group == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", req.ProjectGroup.Parent.ID)) @@ -257,13 +258,13 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje curPGParentPath, err := h.readDB.GetPath(tx, pg.Parent.Type, pg.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } curPGP := path.Join(curPGParentPath, pg.Name) pgParentPath, err := h.readDB.GetPath(tx, req.ProjectGroup.Parent.Type, req.ProjectGroup.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } pgp := path.Join(pgParentPath, req.ProjectGroup.Name) @@ -271,7 +272,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje // check duplicate project group name ap, err := h.readDB.GetProjectGroupByName(tx, req.ProjectGroup.Parent.ID, req.ProjectGroup.Name) if err != nil { - return err + return errors.WithStack(err) } if ap != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with name %q, path %q already exists", req.ProjectGroup.Name, pgp)) @@ -293,18 +294,18 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } pgj, err := json.Marshal(req.ProjectGroup) if err != nil { - return nil, errors.Errorf("failed to marshal project: %w", err) + return nil, errors.Wrapf(err, "failed to marshal project") } actions := []*datamanager.Action{ { @@ -316,7 +317,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje } _, err = h.dm.WriteWal(ctx, actions, cgt) - return req.ProjectGroup, err + return req.ProjectGroup, errors.WithStack(err) } func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectGroupRef string) error { @@ -331,7 +332,7 @@ func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectGroupRef // check project group existance projectGroup, err = h.readDB.GetProjectGroup(tx, projectGroupRef) if err != nil { - return err + return errors.WithStack(err) } if projectGroup == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group %q doesn't exist", projectGroupRef)) @@ -347,13 +348,13 @@ func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectGroupRef cgNames := []string{util.EncodeSha256Hex(projectGroup.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } // TODO(sgotti) implement childs garbage collection @@ -366,5 +367,5 @@ func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectGroupRef } _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } diff --git a/internal/services/configstore/action/remotesource.go b/internal/services/configstore/action/remotesource.go index 0957a7b..b6bceee 100644 --- a/internal/services/configstore/action/remotesource.go +++ b/internal/services/configstore/action/remotesource.go @@ -20,11 +20,12 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" "github.com/gofrs/uuid" - errors "golang.org/x/xerrors" ) func (h *ActionHandler) ValidateRemoteSource(ctx context.Context, remoteSource *types.RemoteSource) error { @@ -66,7 +67,7 @@ func (h *ActionHandler) ValidateRemoteSource(ctx context.Context, remoteSource * func (h *ActionHandler) CreateRemoteSource(ctx context.Context, remoteSource *types.RemoteSource) (*types.RemoteSource, error) { if err := h.ValidateRemoteSource(ctx, remoteSource); err != nil { - return nil, err + return nil, errors.WithStack(err) } var cgt *datamanager.ChangeGroupsUpdateToken @@ -78,13 +79,13 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, remoteSource *ty var err error cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } // check duplicate remoteSource name u, err := h.readDB.GetRemoteSourceByName(tx, remoteSource.Name) if err != nil { - return err + return errors.WithStack(err) } if u != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource %q already exists", u.Name)) @@ -92,14 +93,14 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, remoteSource *ty return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } remoteSource.ID = uuid.Must(uuid.NewV4()).String() rsj, err := json.Marshal(remoteSource) if err != nil { - return nil, errors.Errorf("failed to marshal remotesource: %w", err) + return nil, errors.Wrapf(err, "failed to marshal remotesource") } actions := []*datamanager.Action{ { @@ -111,7 +112,7 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, remoteSource *ty } _, err = h.dm.WriteWal(ctx, actions, cgt) - return remoteSource, err + return remoteSource, errors.WithStack(err) } type UpdateRemoteSourceRequest struct { @@ -122,7 +123,7 @@ type UpdateRemoteSourceRequest struct { func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemoteSourceRequest) (*types.RemoteSource, error) { if err := h.ValidateRemoteSource(ctx, req.RemoteSource); err != nil { - return nil, err + return nil, errors.WithStack(err) } var curRemoteSource *types.RemoteSource @@ -135,7 +136,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot // check remotesource exists curRemoteSource, err = h.readDB.GetRemoteSourceByName(tx, req.RemoteSourceRef) if err != nil { - return err + return errors.WithStack(err) } if curRemoteSource == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource with ref %q doesn't exist", req.RemoteSourceRef)) @@ -145,7 +146,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot // check duplicate remoteSource name u, err := h.readDB.GetRemoteSourceByName(tx, req.RemoteSource.Name) if err != nil { - return err + return errors.WithStack(err) } if u != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource %q already exists", u.Name)) @@ -160,17 +161,17 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot cgNames := []string{util.EncodeSha256Hex("remotesourcename-" + req.RemoteSource.Name), util.EncodeSha256Hex("remotesourceid-" + req.RemoteSource.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } rsj, err := json.Marshal(req.RemoteSource) if err != nil { - return nil, errors.Errorf("failed to marshal remotesource: %w", err) + return nil, errors.Wrapf(err, "failed to marshal remotesource") } actions := []*datamanager.Action{ { @@ -182,7 +183,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot } _, err = h.dm.WriteWal(ctx, actions, cgt) - return req.RemoteSource, err + return req.RemoteSource, errors.WithStack(err) } func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, remoteSourceName string) error { @@ -196,7 +197,7 @@ func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, remoteSourceName // check remoteSource existance remoteSource, err = h.readDB.GetRemoteSourceByName(tx, remoteSourceName) if err != nil { - return err + return errors.WithStack(err) } if remoteSource == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource %q doesn't exist", remoteSourceName)) @@ -206,13 +207,13 @@ func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, remoteSourceName cgNames := []string{util.EncodeSha256Hex("remotesourceid-" + remoteSource.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } actions := []*datamanager.Action{ @@ -225,5 +226,5 @@ func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, remoteSourceName // changegroup is all the remotesources _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } diff --git a/internal/services/configstore/action/secret.go b/internal/services/configstore/action/secret.go index 8c805cb..80f399c 100644 --- a/internal/services/configstore/action/secret.go +++ b/internal/services/configstore/action/secret.go @@ -20,11 +20,12 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" "github.com/gofrs/uuid" - errors "golang.org/x/xerrors" ) func (h *ActionHandler) GetSecret(ctx context.Context, secretID string) (*types.Secret, error) { @@ -32,10 +33,10 @@ func (h *ActionHandler) GetSecret(ctx context.Context, secretID string) (*types. err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error secret, err = h.readDB.GetSecretByID(tx, secretID) - return err + return errors.WithStack(err) }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if secret == nil { @@ -50,17 +51,17 @@ func (h *ActionHandler) GetSecrets(ctx context.Context, parentType types.ConfigT err := h.readDB.Do(ctx, func(tx *db.Tx) error { parentID, err := h.ResolveConfigID(tx, parentType, parentRef) if err != nil { - return err + return errors.WithStack(err) } if tree { secrets, err = h.readDB.GetSecretsTree(tx, parentType, parentID) } else { secrets, err = h.readDB.GetSecrets(tx, parentID) } - return err + return errors.WithStack(err) }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return secrets, nil @@ -97,7 +98,7 @@ func (h *ActionHandler) ValidateSecret(ctx context.Context, secret *types.Secret func (h *ActionHandler) CreateSecret(ctx context.Context, secret *types.Secret) (*types.Secret, error) { if err := h.ValidateSecret(ctx, secret); err != nil { - return nil, err + return nil, errors.WithStack(err) } var cgt *datamanager.ChangeGroupsUpdateToken @@ -109,19 +110,19 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, secret *types.Secret) var err error cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } parentID, err := h.ResolveConfigID(tx, secret.Parent.Type, secret.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } secret.Parent.ID = parentID // check duplicate secret name s, err := h.readDB.GetSecretByName(tx, secret.Parent.ID, secret.Name) if err != nil { - return err + return errors.WithStack(err) } if s != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret with name %q for %s with id %q already exists", secret.Name, secret.Parent.Type, secret.Parent.ID)) @@ -130,14 +131,14 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, secret *types.Secret) return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } secret.ID = uuid.Must(uuid.NewV4()).String() secretj, err := json.Marshal(secret) if err != nil { - return nil, errors.Errorf("failed to marshal secret: %w", err) + return nil, errors.Wrapf(err, "failed to marshal secret") } actions := []*datamanager.Action{ { @@ -149,7 +150,7 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, secret *types.Secret) } _, err = h.dm.WriteWal(ctx, actions, cgt) - return secret, err + return secret, errors.WithStack(err) } type UpdateSecretRequest struct { @@ -160,7 +161,7 @@ type UpdateSecretRequest struct { func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretRequest) (*types.Secret, error) { if err := h.ValidateSecret(ctx, req.Secret); err != nil { - return nil, err + return nil, errors.WithStack(err) } var curSecret *types.Secret @@ -173,14 +174,14 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque parentID, err := h.ResolveConfigID(tx, req.Secret.Parent.Type, req.Secret.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } req.Secret.Parent.ID = parentID // check secret exists curSecret, err = h.readDB.GetSecretByName(tx, req.Secret.Parent.ID, req.SecretName) if err != nil { - return err + return errors.WithStack(err) } if curSecret == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret with name %q for %s with id %q doesn't exists", req.SecretName, req.Secret.Parent.Type, req.Secret.Parent.ID)) @@ -190,7 +191,7 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque // check duplicate secret name u, err := h.readDB.GetSecretByName(tx, req.Secret.Parent.ID, req.Secret.Name) if err != nil { - return err + return errors.WithStack(err) } if u != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret with name %q for %s with id %q already exists", req.Secret.Name, req.Secret.Parent.Type, req.Secret.Parent.ID)) @@ -206,18 +207,18 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque } cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } secretj, err := json.Marshal(req.Secret) if err != nil { - return nil, errors.Errorf("failed to marshal secret: %w", err) + return nil, errors.Wrapf(err, "failed to marshal secret") } actions := []*datamanager.Action{ { @@ -229,7 +230,7 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque } _, err = h.dm.WriteWal(ctx, actions, cgt) - return req.Secret, err + return req.Secret, errors.WithStack(err) } func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.ConfigType, parentRef, secretName string) error { @@ -242,13 +243,13 @@ func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.Confi var err error parentID, err := h.ResolveConfigID(tx, parentType, parentRef) if err != nil { - return err + return errors.WithStack(err) } // check secret existance secret, err = h.readDB.GetSecretByName(tx, parentID, secretName) if err != nil { - return err + return errors.WithStack(err) } if secret == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret with name %q doesn't exist", secretName)) @@ -258,13 +259,13 @@ func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.Confi cgNames := []string{util.EncodeSha256Hex("secretid-" + secret.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } actions := []*datamanager.Action{ @@ -276,5 +277,5 @@ func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.Confi } _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } diff --git a/internal/services/configstore/action/user.go b/internal/services/configstore/action/user.go index f6eeccf..800d659 100644 --- a/internal/services/configstore/action/user.go +++ b/internal/services/configstore/action/user.go @@ -21,12 +21,13 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" "github.com/gofrs/uuid" - errors "golang.org/x/xerrors" ) type CreateUserRequest struct { @@ -54,13 +55,13 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) var err error cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } // check duplicate user name u, err := h.readDB.GetUserByName(tx, req.UserName) if err != nil { - return err + return errors.WithStack(err) } if u != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user with name %q already exists", u.Name)) @@ -69,14 +70,14 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) if req.CreateUserLARequest != nil { rs, err = h.readDB.GetRemoteSourceByName(tx, req.CreateUserLARequest.RemoteSourceName) if err != nil { - return err + return errors.WithStack(err) } if rs == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source %q doesn't exist", req.CreateUserLARequest.RemoteSourceName)) } user, err := h.readDB.GetUserByLinkedAccountRemoteUserIDandSource(tx, req.CreateUserLARequest.RemoteUserID, rs.ID) if err != nil { - return errors.Errorf("failed to get user for remote user id %q and remote source %q: %w", req.CreateUserLARequest.RemoteUserID, rs.ID, err) + return errors.Wrapf(err, "failed to get user for remote user id %q and remote source %q", req.CreateUserLARequest.RemoteUserID, rs.ID) } if user != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for remote user id %q for remote source %q already exists", req.CreateUserLARequest.RemoteUserID, req.CreateUserLARequest.RemoteSourceName)) @@ -85,7 +86,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } user := &types.User{ @@ -114,7 +115,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) userj, err := json.Marshal(user) if err != nil { - return nil, errors.Errorf("failed to marshal user: %w", err) + return nil, errors.Wrapf(err, "failed to marshal user") } // create root user project group @@ -129,7 +130,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) } pgj, err := json.Marshal(pg) if err != nil { - return nil, errors.Errorf("failed to marshal project group: %w", err) + return nil, errors.Wrapf(err, "failed to marshal project group") } actions := []*datamanager.Action{ @@ -148,7 +149,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) } _, err = h.dm.WriteWal(ctx, actions, cgt) - return user, err + return user, errors.WithStack(err) } func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error { @@ -162,7 +163,7 @@ func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error { // check user existance user, err = h.readDB.GetUser(tx, userRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) @@ -172,13 +173,13 @@ func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error { cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } actions := []*datamanager.Action{ @@ -190,7 +191,7 @@ func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error { } _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } type UpdateUserRequest struct { @@ -210,7 +211,7 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest) var err error user, err = h.readDB.GetUser(tx, req.UserRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", req.UserRef)) @@ -218,14 +219,14 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } if req.UserName != "" { // check duplicate user name u, err := h.readDB.GetUserByName(tx, req.UserName) if err != nil { - return err + return errors.WithStack(err) } if u != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user with name %q already exists", u.Name)) @@ -238,7 +239,7 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest) return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if req.UserName != "" { @@ -247,7 +248,7 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest) userj, err := json.Marshal(user) if err != nil { - return nil, errors.Errorf("failed to marshal user: %w", err) + return nil, errors.Wrapf(err, "failed to marshal user") } actions := []*datamanager.Action{ @@ -260,7 +261,7 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest) } _, err = h.dm.WriteWal(ctx, actions, cgt) - return user, err + return user, errors.WithStack(err) } type CreateUserLARequest struct { @@ -293,7 +294,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque var err error user, err = h.readDB.GetUser(tx, req.UserRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", req.UserRef)) @@ -303,12 +304,12 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } rs, err = h.readDB.GetRemoteSourceByName(tx, req.RemoteSourceName) if err != nil { - return err + return errors.WithStack(err) } if rs == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source %q doesn't exist", req.RemoteSourceName)) @@ -316,7 +317,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque user, err := h.readDB.GetUserByLinkedAccountRemoteUserIDandSource(tx, req.RemoteUserID, rs.ID) if err != nil { - return errors.Errorf("failed to get user for remote user id %q and remote source %q: %w", req.RemoteUserID, rs.ID, err) + return errors.Wrapf(err, "failed to get user for remote user id %q and remote source %q", req.RemoteUserID, rs.ID) } if user != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for remote user id %q for remote source %q already exists", req.RemoteUserID, req.RemoteSourceName)) @@ -324,7 +325,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if user.LinkedAccounts == nil { @@ -346,7 +347,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque userj, err := json.Marshal(user) if err != nil { - return nil, errors.Errorf("failed to marshal user: %w", err) + return nil, errors.Wrapf(err, "failed to marshal user") } actions := []*datamanager.Action{ { @@ -358,7 +359,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque } _, err = h.dm.WriteWal(ctx, actions, cgt) - return la, err + return la, errors.WithStack(err) } func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) error { @@ -378,7 +379,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) var err error user, err = h.readDB.GetUser(tx, userRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) @@ -388,13 +389,13 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } _, ok := user.LinkedAccounts[laID] @@ -406,7 +407,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) userj, err := json.Marshal(user) if err != nil { - return errors.Errorf("failed to marshal user: %w", err) + return errors.Wrapf(err, "failed to marshal user") } actions := []*datamanager.Action{ { @@ -418,7 +419,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) } _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } type UpdateUserLARequest struct { @@ -448,7 +449,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque var err error user, err = h.readDB.GetUser(tx, req.UserRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", req.UserRef)) @@ -458,7 +459,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } la, ok := user.LinkedAccounts[req.LinkedAccountID] @@ -468,7 +469,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque rs, err = h.readDB.GetRemoteSource(tx, la.RemoteSourceID) if err != nil { - return err + return errors.WithStack(err) } if rs == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source with id %q doesn't exist", la.RemoteSourceID)) @@ -476,7 +477,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } la := user.LinkedAccounts[req.LinkedAccountID] @@ -490,7 +491,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque userj, err := json.Marshal(user) if err != nil { - return nil, errors.Errorf("failed to marshal user: %w", err) + return nil, errors.Wrapf(err, "failed to marshal user") } actions := []*datamanager.Action{ { @@ -502,7 +503,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque } _, err = h.dm.WriteWal(ctx, actions, cgt) - return la, err + return la, errors.WithStack(err) } func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName string) (string, error) { @@ -522,7 +523,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName var err error user, err = h.readDB.GetUser(tx, userRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) @@ -532,13 +533,13 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return "", err + return "", errors.WithStack(err) } if user.Tokens != nil { if _, ok := user.Tokens[tokenName]; ok { @@ -555,7 +556,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName userj, err := json.Marshal(user) if err != nil { - return "", errors.Errorf("failed to marshal user: %w", err) + return "", errors.Wrapf(err, "failed to marshal user") } actions := []*datamanager.Action{ { @@ -567,7 +568,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName } _, err = h.dm.WriteWal(ctx, actions, cgt) - return token, err + return token, errors.WithStack(err) } func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName string) error { @@ -587,7 +588,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName var err error user, err = h.readDB.GetUser(tx, userRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) @@ -597,13 +598,13 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } _, ok := user.Tokens[tokenName] @@ -615,7 +616,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName userj, err := json.Marshal(user) if err != nil { - return errors.Errorf("failed to marshal user: %w", err) + return errors.Wrapf(err, "failed to marshal user") } actions := []*datamanager.Action{ { @@ -627,7 +628,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName } _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } type UserOrgsResponse struct { @@ -648,17 +649,17 @@ func (h *ActionHandler) GetUserOrgs(ctx context.Context, userRef string) ([]*Use var err error user, err := h.readDB.GetUser(tx, userRef) if err != nil { - return err + return errors.WithStack(err) } if user == nil { return util.NewAPIError(util.ErrNotExist, errors.Errorf("user %q doesn't exist", userRef)) } userOrgs, err = h.readDB.GetUserOrgs(tx, user.ID) - return err + return errors.WithStack(err) }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } res := make([]*UserOrgsResponse, len(userOrgs)) diff --git a/internal/services/configstore/action/variable.go b/internal/services/configstore/action/variable.go index fee92e1..29c88af 100644 --- a/internal/services/configstore/action/variable.go +++ b/internal/services/configstore/action/variable.go @@ -20,11 +20,12 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" "github.com/gofrs/uuid" - errors "golang.org/x/xerrors" ) func (h *ActionHandler) GetVariables(ctx context.Context, parentType types.ConfigType, parentRef string, tree bool) ([]*types.Variable, error) { @@ -32,17 +33,17 @@ func (h *ActionHandler) GetVariables(ctx context.Context, parentType types.Confi err := h.readDB.Do(ctx, func(tx *db.Tx) error { parentID, err := h.ResolveConfigID(tx, parentType, parentRef) if err != nil { - return err + return errors.WithStack(err) } if tree { variables, err = h.readDB.GetVariablesTree(tx, parentType, parentID) } else { variables, err = h.readDB.GetVariables(tx, parentID) } - return err + return errors.WithStack(err) }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return variables, nil @@ -73,7 +74,7 @@ func (h *ActionHandler) ValidateVariable(ctx context.Context, variable *types.Va func (h *ActionHandler) CreateVariable(ctx context.Context, variable *types.Variable) (*types.Variable, error) { if err := h.ValidateVariable(ctx, variable); err != nil { - return nil, err + return nil, errors.WithStack(err) } var cgt *datamanager.ChangeGroupsUpdateToken @@ -85,19 +86,19 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, variable *types.Vari var err error cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } parentID, err := h.ResolveConfigID(tx, variable.Parent.Type, variable.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } variable.Parent.ID = parentID // check duplicate variable name s, err := h.readDB.GetVariableByName(tx, variable.Parent.ID, variable.Name) if err != nil { - return err + return errors.WithStack(err) } if s != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable with name %q for %s with id %q already exists", variable.Name, variable.Parent.Type, variable.Parent.ID)) @@ -106,14 +107,14 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, variable *types.Vari return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } variable.ID = uuid.Must(uuid.NewV4()).String() variablej, err := json.Marshal(variable) if err != nil { - return nil, errors.Errorf("failed to marshal variable: %w", err) + return nil, errors.Wrapf(err, "failed to marshal variable") } actions := []*datamanager.Action{ { @@ -125,7 +126,7 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, variable *types.Vari } _, err = h.dm.WriteWal(ctx, actions, cgt) - return variable, err + return variable, errors.WithStack(err) } type UpdateVariableRequest struct { @@ -136,7 +137,7 @@ type UpdateVariableRequest struct { func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableRequest) (*types.Variable, error) { if err := h.ValidateVariable(ctx, req.Variable); err != nil { - return nil, err + return nil, errors.WithStack(err) } var curVariable *types.Variable @@ -149,14 +150,14 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR parentID, err := h.ResolveConfigID(tx, req.Variable.Parent.Type, req.Variable.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } req.Variable.Parent.ID = parentID // check variable exists curVariable, err = h.readDB.GetVariableByName(tx, req.Variable.Parent.ID, req.VariableName) if err != nil { - return err + return errors.WithStack(err) } if curVariable == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable with name %q for %s with id %q doesn't exists", req.VariableName, req.Variable.Parent.Type, req.Variable.Parent.ID)) @@ -166,7 +167,7 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR // check duplicate variable name u, err := h.readDB.GetVariableByName(tx, req.Variable.Parent.ID, req.Variable.Name) if err != nil { - return err + return errors.WithStack(err) } if u != nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable with name %q for %s with id %q already exists", req.Variable.Name, req.Variable.Parent.Type, req.Variable.Parent.ID)) @@ -182,18 +183,18 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR } cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } variablej, err := json.Marshal(req.Variable) if err != nil { - return nil, errors.Errorf("failed to marshal variable: %w", err) + return nil, errors.Wrapf(err, "failed to marshal variable") } actions := []*datamanager.Action{ { @@ -205,7 +206,7 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR } _, err = h.dm.WriteWal(ctx, actions, cgt) - return req.Variable, err + return req.Variable, errors.WithStack(err) } func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.ConfigType, parentRef, variableName string) error { @@ -218,13 +219,13 @@ func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.Con var err error parentID, err := h.ResolveConfigID(tx, parentType, parentRef) if err != nil { - return err + return errors.WithStack(err) } // check variable existance variable, err = h.readDB.GetVariableByName(tx, parentID, variableName) if err != nil { - return err + return errors.WithStack(err) } if variable == nil { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable with name %q doesn't exist", variableName)) @@ -234,12 +235,12 @@ func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.Con cgNames := []string{util.EncodeSha256Hex("variableid-" + variable.ID)} cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } actions := []*datamanager.Action{ @@ -251,5 +252,5 @@ func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.Con } _, err = h.dm.WriteWal(ctx, actions, cgt) - return err + return errors.WithStack(err) } diff --git a/internal/services/configstore/api/api.go b/internal/services/configstore/api/api.go index fe1ee05..ec56c73 100644 --- a/internal/services/configstore/api/api.go +++ b/internal/services/configstore/api/api.go @@ -18,11 +18,11 @@ import ( "net/http" "net/url" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" "github.com/gorilla/mux" - errors "golang.org/x/xerrors" ) type ErrorResponse struct { @@ -33,7 +33,7 @@ func GetConfigTypeRef(r *http.Request) (types.ConfigType, string, error) { vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong projectref %q: %w", vars["projectref"], err)) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "wrong projectref %q", vars["projectref"])) } if projectRef != "" { return types.ConfigTypeProject, projectRef, nil @@ -41,7 +41,7 @@ func GetConfigTypeRef(r *http.Request) (types.ConfigType, string, error) { projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong projectgroupref %q: %w", vars["projectgroupref"], err)) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "wrong projectgroupref %q", vars["projectgroupref"])) } if projectGroupRef != "" { return types.ConfigTypeProjectGroup, projectGroupRef, nil diff --git a/internal/services/configstore/api/org.go b/internal/services/configstore/api/org.go index bb72b4e..60d68f4 100644 --- a/internal/services/configstore/api/org.go +++ b/internal/services/configstore/api/org.go @@ -20,6 +20,7 @@ import ( "strconv" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/configstore/action" "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" @@ -28,7 +29,6 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) type OrgHandler struct { @@ -49,7 +49,7 @@ func (h *OrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error org, err = h.readDB.GetOrg(tx, orgRef) - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() @@ -146,7 +146,7 @@ func (h *OrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "cannot parse limit"))) return } } @@ -168,7 +168,7 @@ func (h *OrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error orgs, err = h.readDB.GetOrgs(tx, start, limit, asc) - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() diff --git a/internal/services/configstore/api/project.go b/internal/services/configstore/api/project.go index 7e81e20..4aa8580 100644 --- a/internal/services/configstore/api/project.go +++ b/internal/services/configstore/api/project.go @@ -22,6 +22,8 @@ import ( "path" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/services/configstore/action" "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" @@ -35,7 +37,7 @@ import ( func projectResponse(ctx context.Context, readDB *readdb.ReadDB, project *types.Project) (*csapitypes.Project, error) { r, err := projectsResponse(ctx, readDB, []*types.Project{project}) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return r[0], nil } @@ -47,18 +49,18 @@ func projectsResponse(ctx context.Context, readDB *readdb.ReadDB, projects []*ty for i, project := range projects { pp, err := readDB.GetPath(tx, project.Parent.Type, project.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } ownerType, ownerID, err := readDB.GetProjectOwnerID(tx, project) if err != nil { - return err + return errors.WithStack(err) } // calculate global visibility visibility, err := getGlobalVisibility(readDB, tx, project.Visibility, &project.Parent) if err != nil { - return err + return errors.WithStack(err) } // we calculate the path here from parent path since the db could not yet be @@ -76,7 +78,7 @@ func projectsResponse(ctx context.Context, readDB *readdb.ReadDB, projects []*ty return nil }) - return resProjects, err + return resProjects, errors.WithStack(err) } func getGlobalVisibility(readDB *readdb.ReadDB, tx *db.Tx, curVisibility types.Visibility, parent *types.Parent) (types.Visibility, error) { @@ -88,7 +90,7 @@ func getGlobalVisibility(readDB *readdb.ReadDB, tx *db.Tx, curVisibility types.V for curParent.Type == types.ConfigTypeProjectGroup { projectGroup, err := readDB.GetProjectGroupByID(tx, curParent.ID) if err != nil { - return "", err + return "", errors.WithStack(err) } if projectGroup.Visibility == types.VisibilityPrivate { return types.VisibilityPrivate, nil @@ -101,7 +103,7 @@ func getGlobalVisibility(readDB *readdb.ReadDB, tx *db.Tx, curVisibility types.V if curParent.Type == types.ConfigTypeOrg { org, err := readDB.GetOrg(tx, curParent.ID) if err != nil { - return "", err + return "", errors.WithStack(err) } if org.Visibility == types.VisibilityPrivate { return types.VisibilityPrivate, nil diff --git a/internal/services/configstore/api/projectgroup.go b/internal/services/configstore/api/projectgroup.go index ac0bf12..c1ad5a0 100644 --- a/internal/services/configstore/api/projectgroup.go +++ b/internal/services/configstore/api/projectgroup.go @@ -22,6 +22,8 @@ import ( "path" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/services/configstore/action" "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" @@ -35,7 +37,7 @@ import ( func projectGroupResponse(ctx context.Context, readDB *readdb.ReadDB, projectGroup *types.ProjectGroup) (*csapitypes.ProjectGroup, error) { r, err := projectGroupsResponse(ctx, readDB, []*types.ProjectGroup{projectGroup}) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return r[0], nil } @@ -47,18 +49,18 @@ func projectGroupsResponse(ctx context.Context, readDB *readdb.ReadDB, projectGr for i, projectGroup := range projectGroups { pp, err := readDB.GetPath(tx, projectGroup.Parent.Type, projectGroup.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } ownerType, ownerID, err := readDB.GetProjectGroupOwnerID(tx, projectGroup) if err != nil { - return err + return errors.WithStack(err) } // calculate global visibility visibility, err := getGlobalVisibility(readDB, tx, projectGroup.Visibility, &projectGroup.Parent) if err != nil { - return err + return errors.WithStack(err) } // we calculate the path here from parent path since the db could not yet be @@ -76,7 +78,7 @@ func projectGroupsResponse(ctx context.Context, readDB *readdb.ReadDB, projectGr return nil }) - return resProjectGroups, err + return resProjectGroups, errors.WithStack(err) } type ProjectGroupHandler struct { diff --git a/internal/services/configstore/api/remotesource.go b/internal/services/configstore/api/remotesource.go index 875d247..7f6054c 100644 --- a/internal/services/configstore/api/remotesource.go +++ b/internal/services/configstore/api/remotesource.go @@ -20,6 +20,7 @@ import ( "strconv" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/configstore/action" "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" @@ -27,7 +28,6 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) type RemoteSourceHandler struct { @@ -48,7 +48,7 @@ func (h *RemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error remoteSource, err = h.readDB.GetRemoteSource(tx, rsRef) - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() @@ -181,7 +181,7 @@ func (h *RemoteSourcesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var err error limit, err = strconv.Atoi(limitS) if err != nil { - util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "cannot parse limit"))) return } } diff --git a/internal/services/configstore/api/secret.go b/internal/services/configstore/api/secret.go index fcc3012..de1d8d4 100644 --- a/internal/services/configstore/api/secret.go +++ b/internal/services/configstore/api/secret.go @@ -19,6 +19,8 @@ import ( "net/http" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/services/configstore/action" "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" @@ -92,11 +94,11 @@ func (h *SecretsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { for _, s := range resSecrets { pp, err := h.readDB.GetPath(tx, s.Parent.Type, s.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } s.ParentPath = pp } - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() diff --git a/internal/services/configstore/api/user.go b/internal/services/configstore/api/user.go index 73c93be..f67a856 100644 --- a/internal/services/configstore/api/user.go +++ b/internal/services/configstore/api/user.go @@ -20,6 +20,7 @@ import ( "strconv" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" action "agola.io/agola/internal/services/configstore/action" "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" @@ -28,7 +29,6 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) type UserHandler struct { @@ -49,7 +49,7 @@ func (h *UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error user, err = h.readDB.GetUser(tx, userRef) - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() @@ -198,7 +198,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "cannot parse limit"))) return } } @@ -227,7 +227,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error user, err = h.readDB.GetUserByTokenValue(tx, token) - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() @@ -245,7 +245,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error user, err = h.readDB.GetUserByLinkedAccount(tx, linkedAccountID) - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() @@ -264,7 +264,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error user, err = h.readDB.GetUserByLinkedAccountRemoteUserIDandSource(tx, remoteUserID, remoteSourceID) - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() @@ -281,7 +281,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error users, err = h.readDB.GetUsers(tx, start, limit, asc) - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() diff --git a/internal/services/configstore/api/variable.go b/internal/services/configstore/api/variable.go index ee9a5a2..b0a184d 100644 --- a/internal/services/configstore/api/variable.go +++ b/internal/services/configstore/api/variable.go @@ -19,6 +19,8 @@ import ( "net/http" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/services/configstore/action" "agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/util" @@ -65,11 +67,11 @@ func (h *VariablesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { for _, v := range resVariables { pp, err := h.readDB.GetPath(tx, v.Parent.Type, v.Parent.ID) if err != nil { - return err + return errors.WithStack(err) } v.ParentPath = pp } - return err + return errors.WithStack(err) }) if err != nil { h.log.Err(err).Send() diff --git a/internal/services/configstore/common/common.go b/internal/services/configstore/common/common.go index 83904b7..f14e7ad 100644 --- a/internal/services/configstore/common/common.go +++ b/internal/services/configstore/common/common.go @@ -18,6 +18,7 @@ import ( "net/url" "strings" + "agola.io/agola/internal/errors" "github.com/gofrs/uuid" ) @@ -38,7 +39,7 @@ const ( func ParsePathRef(ref string) (RefType, error) { ref, err := url.PathUnescape(ref) if err != nil { - return -1, err + return -1, errors.WithStack(err) } if strings.Contains(ref, "/") { return RefTypePath, nil diff --git a/internal/services/configstore/configstore.go b/internal/services/configstore/configstore.go index 685d0c7..27f4588 100644 --- a/internal/services/configstore/configstore.go +++ b/internal/services/configstore/configstore.go @@ -24,6 +24,7 @@ import ( scommon "agola.io/agola/internal/common" "agola.io/agola/internal/datamanager" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/services/config" @@ -39,7 +40,6 @@ import ( "github.com/rs/zerolog/log" etcdclientv3 "go.etcd.io/etcd/clientv3" "go.etcd.io/etcd/mvcc/mvccpb" - errors "golang.org/x/xerrors" ) func (s *Configstore) maintenanceModeWatcherLoop(ctx context.Context, runCtxCancel context.CancelFunc, maintenanceModeEnabled bool) { @@ -64,7 +64,7 @@ func (s *Configstore) maintenanceModeWatcher(ctx context.Context, runCtxCancel c log.Info().Msgf("watcher: maintenance mode enabled: %t", maintenanceModeEnabled) resp, err := s.e.Get(ctx, common.EtcdMaintenanceKey, 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if len(resp.Kvs) > 0 { @@ -83,7 +83,7 @@ func (s *Configstore) maintenanceModeWatcher(ctx context.Context, runCtxCancel c for wresp := range wch { if wresp.Canceled { - return wresp.Err() + return errors.WithStack(wresp.Err()) } for _, ev := range wresp.Events { @@ -124,11 +124,11 @@ func NewConfigstore(ctx context.Context, log zerolog.Logger, c *config.Configsto ost, err := scommon.NewObjectStorage(&c.ObjectStorage) if err != nil { - return nil, err + return nil, errors.WithStack(err) } e, err := scommon.NewEtcd(&c.Etcd, log, "configstore") if err != nil { - return nil, err + return nil, errors.WithStack(err) } cs := &Configstore{ @@ -155,11 +155,11 @@ func NewConfigstore(ctx context.Context, log zerolog.Logger, c *config.Configsto } dm, err := datamanager.NewDataManager(ctx, log, dmConf) if err != nil { - return nil, err + return nil, errors.WithStack(err) } readDB, err := readdb.NewReadDB(ctx, log, filepath.Join(c.DataDir, "readdb"), e, ost, dm) if err != nil { - return nil, err + return nil, errors.WithStack(err) } cs.dm = dm @@ -340,13 +340,13 @@ func (s *Configstore) run(ctx context.Context) error { tlsConfig, err = util.NewTLSConfig(s.c.Web.TLSCertFile, s.c.Web.TLSKeyFile, "", false) if err != nil { s.log.Err(err).Send() - return err + return errors.WithStack(err) } } resp, err := s.e.Get(ctx, common.EtcdMaintenanceKey, 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } maintenanceMode := false @@ -405,12 +405,12 @@ func (s *Configstore) run(ctx context.Context) error { case err := <-lerrCh: if err != nil { log.Err(err).Msgf("http server listen error") - return err + return errors.WithStack(err) } case err := <-errCh: if err != nil { s.log.Err(err).Send() - return err + return errors.WithStack(err) } } @@ -418,5 +418,5 @@ func (s *Configstore) run(ctx context.Context) error { httpServer.Close() wg.Wait() - return err + return errors.WithStack(err) } diff --git a/internal/services/configstore/configstore_test.go b/internal/services/configstore/configstore_test.go index 3ec8e46..d04ad9a 100644 --- a/internal/services/configstore/configstore_test.go +++ b/internal/services/configstore/configstore_test.go @@ -28,6 +28,8 @@ import ( "time" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/services/config" "agola.io/agola/internal/services/configstore/action" "agola.io/agola/internal/testutil" @@ -106,9 +108,9 @@ func getProjects(ctx context.Context, cs *Configstore) ([]*types.Project, error) err := cs.readDB.Do(ctx, func(tx *db.Tx) error { var err error projects, err = cs.readDB.GetAllProjects(tx) - return err + return errors.WithStack(err) }) - return projects, err + return projects, errors.WithStack(err) } func getUsers(ctx context.Context, cs *Configstore) ([]*types.User, error) { @@ -116,9 +118,9 @@ func getUsers(ctx context.Context, cs *Configstore) ([]*types.User, error) { err := cs.readDB.Do(ctx, func(tx *db.Tx) error { var err error users, err = cs.readDB.GetUsers(tx, "", 0, true) - return err + return errors.WithStack(err) }) - return users, err + return users, errors.WithStack(err) } func TestResync(t *testing.T) { @@ -1320,7 +1322,7 @@ func TestRemoteSource(t *testing.T) { t.Fatalf("unexpected err: %v", err) } - expectedError := util.NewAPIError(util.ErrBadRequest, fmt.Errorf(`remotesource "rs01" already exists`)) + expectedError := util.NewAPIError(util.ErrBadRequest, errors.Errorf(`remotesource "rs01" already exists`)) _, err = cs.ah.CreateRemoteSource(ctx, rs) if err.Error() != expectedError.Error() { t.Fatalf("expected err: %v, got err: %v", expectedError.Error(), err.Error()) @@ -1409,7 +1411,7 @@ func TestRemoteSource(t *testing.T) { t.Fatalf("unexpected err: %v", err) } - expectedError := util.NewAPIError(util.ErrBadRequest, fmt.Errorf(`remotesource "rs02" already exists`)) + expectedError := util.NewAPIError(util.ErrBadRequest, errors.Errorf(`remotesource "rs02" already exists`)) rs01.Name = "rs02" req := &action.UpdateRemoteSourceRequest{ RemoteSourceRef: "rs01", diff --git a/internal/services/configstore/readdb/org.go b/internal/services/configstore/readdb/org.go index 8c7960f..c807fa9 100644 --- a/internal/services/configstore/readdb/org.go +++ b/internal/services/configstore/readdb/org.go @@ -19,12 +19,12 @@ import ( "encoding/json" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/configstore/common" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" sq "github.com/Masterminds/squirrel" - errors "golang.org/x/xerrors" ) var ( @@ -38,19 +38,19 @@ var ( func (r *ReadDB) insertOrg(tx *db.Tx, data []byte) error { org := types.Organization{} if err := json.Unmarshal(data, &org); err != nil { - return errors.Errorf("failed to unmarshal org: %w", err) + return errors.Wrapf(err, "failed to unmarshal org") } r.log.Debug().Msgf("inserting org: %s", util.Dump(org)) // poor man insert or update... if err := r.deleteOrg(tx, org.ID); err != nil { - return err + return errors.WithStack(err) } q, args, err := orgInsert.Values(org.ID, org.Name, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err := tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert org: %w", err) + return errors.Wrapf(err, "failed to insert org") } return nil @@ -58,7 +58,7 @@ func (r *ReadDB) insertOrg(tx *db.Tx, data []byte) error { func (r *ReadDB) deleteOrg(tx *db.Tx, orgID string) error { if _, err := tx.Exec("delete from org where id = $1", orgID); err != nil { - return errors.Errorf("failed to delete org: %w", err) + return errors.Wrapf(err, "failed to delete org") } return nil } @@ -66,7 +66,7 @@ func (r *ReadDB) deleteOrg(tx *db.Tx, orgID string) error { func (r *ReadDB) GetOrg(tx *db.Tx, orgRef string) (*types.Organization, error) { refType, err := common.ParseNameRef(orgRef) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var org *types.Organization @@ -76,19 +76,19 @@ func (r *ReadDB) GetOrg(tx *db.Tx, orgRef string) (*types.Organization, error) { case common.RefTypeName: org, err = r.GetOrgByName(tx, orgRef) } - return org, err + return org, errors.WithStack(err) } func (r *ReadDB) GetOrgByID(tx *db.Tx, orgID string) (*types.Organization, error) { q, args, err := orgSelect.Where(sq.Eq{"id": orgID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } orgs, _, err := fetchOrgs(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(orgs) > 1 { return nil, errors.Errorf("too many rows returned") @@ -103,12 +103,12 @@ func (r *ReadDB) GetOrgByName(tx *db.Tx, name string) (*types.Organization, erro q, args, err := orgSelect.Where(sq.Eq{"name": name}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } orgs, _, err := fetchOrgs(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(orgs) > 1 { return nil, errors.Errorf("too many rows returned") @@ -149,22 +149,22 @@ func (r *ReadDB) GetOrgs(tx *db.Tx, startOrgName string, limit int, asc bool) ([ q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } rows, err := tx.Query(q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } orgs, _, err = scanOrgs(rows) - return orgs, err + return orgs, errors.WithStack(err) } func fetchOrgs(tx *db.Tx, q string, args ...interface{}) ([]*types.Organization, []string, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } defer rows.Close() return scanOrgs(rows) @@ -174,12 +174,12 @@ func scanOrg(rows *sql.Rows, additionalFields ...interface{}) (*types.Organizati var id string var data []byte if err := rows.Scan(&id, &data); err != nil { - return nil, "", errors.Errorf("failed to scan rows: %w", err) + return nil, "", errors.Wrapf(err, "failed to scan rows") } org := types.Organization{} if len(data) > 0 { if err := json.Unmarshal(data, &org); err != nil { - return nil, "", errors.Errorf("failed to unmarshal org: %w", err) + return nil, "", errors.Wrapf(err, "failed to unmarshal org") } } @@ -193,13 +193,13 @@ func scanOrgs(rows *sql.Rows) ([]*types.Organization, []string, error) { org, id, err := scanOrg(rows) if err != nil { rows.Close() - return nil, nil, err + return nil, nil, errors.WithStack(err) } orgs = append(orgs, org) ids = append(ids, id) } if err := rows.Err(); err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } return orgs, ids, nil } @@ -207,19 +207,19 @@ func scanOrgs(rows *sql.Rows) ([]*types.Organization, []string, error) { func (r *ReadDB) insertOrgMember(tx *db.Tx, data []byte) error { orgmember := types.OrganizationMember{} if err := json.Unmarshal(data, &orgmember); err != nil { - return errors.Errorf("failed to unmarshal orgmember: %w", err) + return errors.Wrapf(err, "failed to unmarshal orgmember") } r.log.Debug().Msgf("inserting orgmember: %s", util.Dump(orgmember)) // poor man insert or update... if err := r.deleteOrgMember(tx, orgmember.ID); err != nil { - return err + return errors.WithStack(err) } q, args, err := orgmemberInsert.Values(orgmember.ID, orgmember.OrganizationID, orgmember.UserID, orgmember.MemberRole, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err := tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert orgmember: %w", err) + return errors.Wrapf(err, "failed to insert orgmember") } return nil @@ -227,7 +227,7 @@ func (r *ReadDB) insertOrgMember(tx *db.Tx, data []byte) error { func (r *ReadDB) deleteOrgMember(tx *db.Tx, orgmemberID string) error { if _, err := tx.Exec("delete from orgmember where id = $1", orgmemberID); err != nil { - return errors.Errorf("failed to delete orgmember: %w", err) + return errors.Wrapf(err, "failed to delete orgmember") } return nil } @@ -236,12 +236,12 @@ func (r *ReadDB) GetOrgMemberByOrgUserID(tx *db.Tx, orgID, userID string) (*type q, args, err := orgmemberSelect.Where(sq.Eq{"orgmember.orgid": orgID, "orgmember.userid": userID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } oms, _, err := fetchOrgMembers(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(oms) > 1 { return nil, errors.Errorf("too many rows returned") @@ -255,7 +255,7 @@ func (r *ReadDB) GetOrgMemberByOrgUserID(tx *db.Tx, orgID, userID string) (*type func fetchOrgMembers(tx *db.Tx, q string, args ...interface{}) ([]*types.OrganizationMember, []string, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } defer rows.Close() return scanOrgMembers(rows) @@ -265,12 +265,12 @@ func scanOrgMember(rows *sql.Rows, additionalFields ...interface{}) (*types.Orga var id string var data []byte if err := rows.Scan(&id, &data); err != nil { - return nil, "", errors.Errorf("failed to scan rows: %w", err) + return nil, "", errors.Wrapf(err, "failed to scan rows") } orgmember := types.OrganizationMember{} if len(data) > 0 { if err := json.Unmarshal(data, &orgmember); err != nil { - return nil, "", errors.Errorf("failed to unmarshal org: %w", err) + return nil, "", errors.Wrapf(err, "failed to unmarshal org") } } @@ -284,13 +284,13 @@ func scanOrgMembers(rows *sql.Rows) ([]*types.OrganizationMember, []string, erro orgmember, id, err := scanOrgMember(rows) if err != nil { rows.Close() - return nil, nil, err + return nil, nil, errors.WithStack(err) } orgmembers = append(orgmembers, orgmember) ids = append(ids, id) } if err := rows.Err(); err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } return orgmembers, ids, nil } @@ -309,12 +309,12 @@ func (r *ReadDB) GetOrgUsers(tx *db.Tx, orgID string) ([]*OrgUser, error) { q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } rows, err := tx.Query(q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer rows.Close() @@ -325,13 +325,13 @@ func (r *ReadDB) GetOrgUsers(tx *db.Tx, orgID string) ([]*OrgUser, error) { var orgmemberdata []byte var userdata []byte if err := rows.Scan(&orgmemberdata, &userdata); err != nil { - return nil, errors.Errorf("failed to scan rows: %w", err) + return nil, errors.Wrapf(err, "failed to scan rows") } if err := json.Unmarshal(orgmemberdata, &orgmember); err != nil { - return nil, errors.Errorf("failed to unmarshal orgmember: %w", err) + return nil, errors.Wrapf(err, "failed to unmarshal orgmember") } if err := json.Unmarshal(userdata, &user); err != nil { - return nil, errors.Errorf("failed to unmarshal org: %w", err) + return nil, errors.Wrapf(err, "failed to unmarshal org") } orgusers = append(orgusers, &OrgUser{ @@ -340,7 +340,7 @@ func (r *ReadDB) GetOrgUsers(tx *db.Tx, orgID string) ([]*OrgUser, error) { }) } if err := rows.Err(); err != nil { - return nil, err + return nil, errors.WithStack(err) } return orgusers, nil @@ -360,12 +360,12 @@ func (r *ReadDB) GetUserOrgs(tx *db.Tx, userID string) ([]*UserOrg, error) { q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } rows, err := tx.Query(q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer rows.Close() @@ -376,13 +376,13 @@ func (r *ReadDB) GetUserOrgs(tx *db.Tx, userID string) ([]*UserOrg, error) { var orgmemberdata []byte var orgdata []byte if err := rows.Scan(&orgmemberdata, &orgdata); err != nil { - return nil, errors.Errorf("failed to scan rows: %w", err) + return nil, errors.Wrapf(err, "failed to scan rows") } if err := json.Unmarshal(orgmemberdata, &orgmember); err != nil { - return nil, errors.Errorf("failed to unmarshal orgmember: %w", err) + return nil, errors.Wrapf(err, "failed to unmarshal orgmember") } if err := json.Unmarshal(orgdata, &org); err != nil { - return nil, errors.Errorf("failed to unmarshal org: %w", err) + return nil, errors.Wrapf(err, "failed to unmarshal org") } userorgs = append(userorgs, &UserOrg{ @@ -391,7 +391,7 @@ func (r *ReadDB) GetUserOrgs(tx *db.Tx, userID string) ([]*UserOrg, error) { }) } if err := rows.Err(); err != nil { - return nil, err + return nil, errors.WithStack(err) } return userorgs, nil diff --git a/internal/services/configstore/readdb/project.go b/internal/services/configstore/readdb/project.go index 2dcb2ff..40ae604 100644 --- a/internal/services/configstore/readdb/project.go +++ b/internal/services/configstore/readdb/project.go @@ -21,12 +21,12 @@ import ( "strings" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/configstore/common" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" sq "github.com/Masterminds/squirrel" - errors "golang.org/x/xerrors" ) var ( @@ -37,18 +37,18 @@ var ( func (r *ReadDB) insertProject(tx *db.Tx, data []byte) error { var project *types.Project if err := json.Unmarshal(data, &project); err != nil { - return errors.Errorf("failed to unmarshal project: %w", err) + return errors.Wrapf(err, "failed to unmarshal project") } // poor man insert or update... if err := r.deleteProject(tx, project.ID); err != nil { - return err + return errors.WithStack(err) } q, args, err := projectInsert.Values(project.ID, project.Name, project.Parent.ID, project.Parent.Type, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert project: %w", err) + return errors.Wrapf(err, "failed to insert project") } return nil @@ -57,7 +57,7 @@ func (r *ReadDB) insertProject(tx *db.Tx, data []byte) error { func (r *ReadDB) deleteProject(tx *db.Tx, id string) error { // poor man insert or update... if _, err := tx.Exec("delete from project where id = $1", id); err != nil { - return errors.Errorf("failed to delete project: %w", err) + return errors.Wrapf(err, "failed to delete project") } return nil } @@ -65,14 +65,14 @@ func (r *ReadDB) deleteProject(tx *db.Tx, id string) error { func (r *ReadDB) GetProjectPath(tx *db.Tx, project *types.Project) (string, error) { pgroup, err := r.GetProjectGroup(tx, project.Parent.ID) if err != nil { - return "", err + return "", errors.WithStack(err) } if pgroup == nil { return "", errors.Errorf("parent group %q for project %q doesn't exist", project.Parent.ID, project.ID) } p, err := r.GetProjectGroupPath(tx, pgroup) if err != nil { - return "", err + return "", errors.WithStack(err) } p = path.Join(p, project.Name) @@ -83,7 +83,7 @@ func (r *ReadDB) GetProjectPath(tx *db.Tx, project *types.Project) (string, erro func (r *ReadDB) GetProjectOwnerID(tx *db.Tx, project *types.Project) (types.ConfigType, string, error) { pgroup, err := r.GetProjectGroup(tx, project.Parent.ID) if err != nil { - return "", "", err + return "", "", errors.WithStack(err) } if pgroup == nil { return "", "", errors.Errorf("parent group %q for project %q doesn't exist", project.Parent.ID, project.ID) @@ -94,7 +94,7 @@ func (r *ReadDB) GetProjectOwnerID(tx *db.Tx, project *types.Project) (types.Con func (r *ReadDB) GetProject(tx *db.Tx, projectRef string) (*types.Project, error) { projectRefType, err := common.ParsePathRef(projectRef) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var project *types.Project @@ -104,19 +104,19 @@ func (r *ReadDB) GetProject(tx *db.Tx, projectRef string) (*types.Project, error case common.RefTypePath: project, err = r.GetProjectByPath(tx, projectRef) } - return project, err + return project, errors.WithStack(err) } func (r *ReadDB) GetProjectByID(tx *db.Tx, projectID string) (*types.Project, error) { q, args, err := projectSelect.Where(sq.Eq{"id": projectID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } projects, _, err := fetchProjects(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(projects) > 1 { return nil, errors.Errorf("too many rows returned") @@ -131,12 +131,12 @@ func (r *ReadDB) GetProjectByName(tx *db.Tx, parentID, name string) (*types.Proj q, args, err := projectSelect.Where(sq.Eq{"parentid": parentID, "name": name}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } projects, _, err := fetchProjects(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(projects) > 1 { return nil, errors.Errorf("too many rows returned") @@ -156,7 +156,7 @@ func (r *ReadDB) GetProjectByPath(tx *db.Tx, projectPath string) (*types.Project projectName := path.Base(projectPath) projectGroup, err := r.GetProjectGroupByPath(tx, projectGroupPath) if err != nil { - return nil, errors.Errorf("failed to get project group %q: %w", projectGroupPath, err) + return nil, errors.Wrapf(err, "failed to get project group %q", projectGroupPath) } if projectGroup == nil { return nil, nil @@ -164,7 +164,7 @@ func (r *ReadDB) GetProjectByPath(tx *db.Tx, projectPath string) (*types.Project project, err := r.GetProjectByName(tx, projectGroup.ID, projectName) if err != nil { - return nil, errors.Errorf("failed to get project group %q: %w", projectName, err) + return nil, errors.Wrapf(err, "failed to get project group %q", projectName) } return project, nil } @@ -175,17 +175,17 @@ func (r *ReadDB) GetProjectGroupProjects(tx *db.Tx, parentID string) ([]*types.P q, args, err := projectSelect.Where(sq.Eq{"parentid": parentID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } projects, _, err = fetchProjects(tx, q, args...) - return projects, err + return projects, errors.WithStack(err) } func fetchProjects(tx *db.Tx, q string, args ...interface{}) ([]*types.Project, []string, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } defer rows.Close() return scanProjects(rows) @@ -195,12 +195,12 @@ func scanProject(rows *sql.Rows, additionalFields ...interface{}) (*types.Projec var id string var data []byte if err := rows.Scan(&id, &data); err != nil { - return nil, "", errors.Errorf("failed to scan rows: %w", err) + return nil, "", errors.Wrapf(err, "failed to scan rows") } project := types.Project{} if len(data) > 0 { if err := json.Unmarshal(data, &project); err != nil { - return nil, "", errors.Errorf("failed to unmarshal project: %w", err) + return nil, "", errors.Wrapf(err, "failed to unmarshal project") } } @@ -214,13 +214,13 @@ func scanProjects(rows *sql.Rows) ([]*types.Project, []string, error) { p, id, err := scanProject(rows) if err != nil { rows.Close() - return nil, nil, err + return nil, nil, errors.WithStack(err) } projects = append(projects, p) ids = append(ids, id) } if err := rows.Err(); err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } return projects, ids, nil } @@ -233,9 +233,9 @@ func (r *ReadDB) GetAllProjects(tx *db.Tx) ([]*types.Project, error) { q, args, err := projectSelect.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } projects, _, err = fetchProjects(tx, q, args...) - return projects, err + return projects, errors.WithStack(err) } diff --git a/internal/services/configstore/readdb/projectgroup.go b/internal/services/configstore/readdb/projectgroup.go index dd689ff..a776ab8 100644 --- a/internal/services/configstore/readdb/projectgroup.go +++ b/internal/services/configstore/readdb/projectgroup.go @@ -21,12 +21,12 @@ import ( "strings" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/configstore/common" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" sq "github.com/Masterminds/squirrel" - errors "golang.org/x/xerrors" ) var ( @@ -37,19 +37,19 @@ var ( func (r *ReadDB) insertProjectGroup(tx *db.Tx, data []byte) error { var group *types.ProjectGroup if err := json.Unmarshal(data, &group); err != nil { - return errors.Errorf("failed to unmarshal group: %w", err) + return errors.Wrapf(err, "failed to unmarshal group") } // poor man insert or update... if err := r.deleteProjectGroup(tx, group.ID); err != nil { - return err + return errors.WithStack(err) } q, args, err := projectgroupInsert.Values(group.ID, group.Name, group.Parent.ID, group.Parent.Type, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert group: %w", err) + return errors.Wrapf(err, "failed to insert group") } return nil @@ -58,7 +58,7 @@ func (r *ReadDB) insertProjectGroup(tx *db.Tx, data []byte) error { func (r *ReadDB) deleteProjectGroup(tx *db.Tx, id string) error { // poor man insert or update... if _, err := tx.Exec("delete from projectgroup where id = $1", id); err != nil { - return errors.Errorf("failed to delete group: %w", err) + return errors.Wrapf(err, "failed to delete group") } return nil } @@ -87,7 +87,7 @@ func (r *ReadDB) GetProjectGroupHierarchy(tx *db.Tx, projectGroup *types.Project var err error projectGroup, err = r.GetProjectGroup(tx, projectGroupID) if err != nil { - return nil, errors.Errorf("failed to get project group %q: %w", projectGroupID, err) + return nil, errors.Wrapf(err, "failed to get project group %q", projectGroupID) } if projectGroup == nil { return nil, errors.Errorf("project group %q doesn't exist", projectGroupID) @@ -112,7 +112,7 @@ func (r *ReadDB) GetProjectGroupPath(tx *db.Tx, group *types.ProjectGroup) (stri groups, err := r.GetProjectGroupHierarchy(tx, group) if err != nil { - return "", err + return "", errors.WithStack(err) } rootGroupType := groups[0].ParentType @@ -124,7 +124,7 @@ func (r *ReadDB) GetProjectGroupPath(tx *db.Tx, group *types.ProjectGroup) (stri var err error p, err = r.GetPath(tx, rootGroupType, rootGroupID) if err != nil { - return "", err + return "", errors.WithStack(err) } default: return "", errors.Errorf("invalid root group type %q", rootGroupType) @@ -140,7 +140,7 @@ func (r *ReadDB) GetProjectGroupPath(tx *db.Tx, group *types.ProjectGroup) (stri func (r *ReadDB) GetProjectGroupOwnerID(tx *db.Tx, group *types.ProjectGroup) (types.ConfigType, string, error) { groups, err := r.GetProjectGroupHierarchy(tx, group) if err != nil { - return "", "", err + return "", "", errors.WithStack(err) } rootGroupType := groups[0].ParentType @@ -151,7 +151,7 @@ func (r *ReadDB) GetProjectGroupOwnerID(tx *db.Tx, group *types.ProjectGroup) (t func (r *ReadDB) GetProjectGroup(tx *db.Tx, projectGroupRef string) (*types.ProjectGroup, error) { groupRef, err := common.ParsePathRef(projectGroupRef) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var group *types.ProjectGroup @@ -161,19 +161,19 @@ func (r *ReadDB) GetProjectGroup(tx *db.Tx, projectGroupRef string) (*types.Proj case common.RefTypePath: group, err = r.GetProjectGroupByPath(tx, projectGroupRef) } - return group, err + return group, errors.WithStack(err) } func (r *ReadDB) GetProjectGroupByID(tx *db.Tx, projectGroupID string) (*types.ProjectGroup, error) { q, args, err := projectgroupSelect.Where(sq.Eq{"id": projectGroupID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } projectGroups, _, err := fetchProjectGroups(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(projectGroups) > 1 { return nil, errors.Errorf("too many rows returned") @@ -188,12 +188,12 @@ func (r *ReadDB) GetProjectGroupByName(tx *db.Tx, parentID, name string) (*types q, args, err := projectgroupSelect.Where(sq.Eq{"parentid": parentID, "name": name}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } projectGroups, _, err := fetchProjectGroups(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(projectGroups) > 1 { return nil, errors.Errorf("too many rows returned") @@ -214,7 +214,7 @@ func (r *ReadDB) GetProjectGroupByPath(tx *db.Tx, projectGroupPath string) (*typ case "org": org, err := r.GetOrgByName(tx, parts[1]) if err != nil { - return nil, errors.Errorf("failed to get org %q: %w", parts[1], err) + return nil, errors.Wrapf(err, "failed to get org %q", parts[1]) } if org == nil { return nil, errors.Errorf("cannot find org with name %q", parts[1]) @@ -223,7 +223,7 @@ func (r *ReadDB) GetProjectGroupByPath(tx *db.Tx, projectGroupPath string) (*typ case "user": user, err := r.GetUserByName(tx, parts[1]) if err != nil { - return nil, errors.Errorf("failed to get user %q: %w", parts[1], err) + return nil, errors.Wrapf(err, "failed to get user %q", parts[1]) } if user == nil { return nil, errors.Errorf("cannot find user with name %q", parts[1]) @@ -239,7 +239,7 @@ func (r *ReadDB) GetProjectGroupByPath(tx *db.Tx, projectGroupPath string) (*typ var err error projectGroup, err = r.GetProjectGroupByName(tx, parentID, projectGroupName) if err != nil { - return nil, errors.Errorf("failed to get project group %q: %w", projectGroupName, err) + return nil, errors.Wrapf(err, "failed to get project group %q", projectGroupName) } if projectGroup == nil { return nil, nil @@ -256,17 +256,17 @@ func (r *ReadDB) GetProjectGroupSubgroups(tx *db.Tx, parentID string) ([]*types. q, args, err := projectgroupSelect.Where(sq.Eq{"parentid": parentID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } projectGroups, _, err = fetchProjectGroups(tx, q, args...) - return projectGroups, err + return projectGroups, errors.WithStack(err) } func fetchProjectGroups(tx *db.Tx, q string, args ...interface{}) ([]*types.ProjectGroup, []string, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } defer rows.Close() return scanProjectGroups(rows) @@ -276,12 +276,12 @@ func scanProjectGroup(rows *sql.Rows, additionalFields ...interface{}) (*types.P var id string var data []byte if err := rows.Scan(&id, &data); err != nil { - return nil, "", errors.Errorf("failed to scan rows: %w", err) + return nil, "", errors.Wrapf(err, "failed to scan rows") } group := types.ProjectGroup{} if len(data) > 0 { if err := json.Unmarshal(data, &group); err != nil { - return nil, "", errors.Errorf("failed to unmarshal group: %w", err) + return nil, "", errors.Wrapf(err, "failed to unmarshal group") } } @@ -295,13 +295,13 @@ func scanProjectGroups(rows *sql.Rows) ([]*types.ProjectGroup, []string, error) p, id, err := scanProjectGroup(rows) if err != nil { rows.Close() - return nil, nil, err + return nil, nil, errors.WithStack(err) } projectGroups = append(projectGroups, p) ids = append(ids, id) } if err := rows.Err(); err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } return projectGroups, ids, nil } diff --git a/internal/services/configstore/readdb/readdb.go b/internal/services/configstore/readdb/readdb.go index d794513..a7eac42 100644 --- a/internal/services/configstore/readdb/readdb.go +++ b/internal/services/configstore/readdb/readdb.go @@ -26,6 +26,7 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/sequence" @@ -34,7 +35,6 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) var ( @@ -65,7 +65,7 @@ type ReadDB struct { func NewReadDB(ctx context.Context, log zerolog.Logger, dataDir string, e *etcd.Store, ost *objectstorage.ObjStorage, dm *datamanager.DataManager) (*ReadDB, error) { if err := os.MkdirAll(dataDir, 0770); err != nil { - return nil, err + return nil, errors.WithStack(err) } readDB := &ReadDB{ @@ -96,7 +96,7 @@ func (r *ReadDB) IsInitialized() bool { func (r *ReadDB) Initialize(ctx context.Context) error { // sync the rdb if err := r.SyncRDB(ctx); err != nil { - return errors.Errorf("error syncing db: %w", err) + return errors.Wrapf(err, "error syncing db") } return nil } @@ -109,17 +109,17 @@ func (r *ReadDB) ResetDB(ctx context.Context) error { // drop rdb if err := os.Remove(filepath.Join(r.dataDir, "db")); err != nil { - return err + return errors.WithStack(err) } rdb, err := db.NewDB(db.Sqlite3, filepath.Join(r.dataDir, "db")) if err != nil { - return err + return errors.WithStack(err) } // populate readdb if err := rdb.Create(ctx, Stmts); err != nil { - return err + return errors.WithStack(err) } r.rdb = rdb @@ -130,13 +130,13 @@ func (r *ReadDB) ResetDB(ctx context.Context) error { func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) { dumpIndex, err := r.dm.GetLastDataStatus() if err != nil { - return "", err + return "", errors.WithStack(err) } for dataType, files := range dumpIndex.Files { for _, file := range files { dumpf, err := r.ost.ReadObject(r.dm.DataFilePath(dataType, file.ID)) if err != nil { - return "", err + return "", errors.WithStack(err) } dumpEntries := []*datamanager.DataEntry{} dec := json.NewDecoder(dumpf) @@ -150,7 +150,7 @@ func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) { } if err != nil { dumpf.Close() - return "", err + return "", errors.WithStack(err) } dumpEntries = append(dumpEntries, de) } @@ -165,25 +165,25 @@ func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) { Data: de.Data, } if err := r.applyAction(tx, action); err != nil { - return err + return errors.WithStack(err) } } return nil }) if err != nil { - return "", err + return "", errors.WithStack(err) } } } err = r.rdb.Do(ctx, func(tx *db.Tx) error { if err := r.insertCommittedWalSequence(tx, dumpIndex.WalSequence); err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return "", err + return "", errors.WithStack(err) } return dumpIndex.WalSequence, nil @@ -195,18 +195,18 @@ func (r *ReadDB) SyncFromWals(ctx context.Context, startWalSeq, endWalSeq string for _, walFile := range walFiles { header, err := r.dm.ReadWal(walFile.WalSequence) if err != nil { - return err + return errors.WithStack(err) } if err := r.insertCommittedWalSequence(tx, walFile.WalSequence); err != nil { - return err + return errors.WithStack(err) } if err := r.applyWal(tx, header.WalDataFileID); err != nil { - return err + return errors.WithStack(err) } } return nil }) - return err + return errors.WithStack(err) } lastWalSeq := startWalSeq @@ -218,7 +218,7 @@ func (r *ReadDB) SyncFromWals(ctx context.Context, startWalSeq, endWalSeq string for walFile := range r.dm.ListOSTWals(startWalSeq) { if walFile.Err != nil { - return "", walFile.Err + return "", errors.WithStack(walFile.Err) } walFiles = append(walFiles, walFile) @@ -226,7 +226,7 @@ func (r *ReadDB) SyncFromWals(ctx context.Context, startWalSeq, endWalSeq string if count > 100 { if err := insertfunc(walFiles); err != nil { - return "", err + return "", errors.WithStack(err) } count = 0 walFiles = []*datamanager.WalFile{} @@ -235,7 +235,7 @@ func (r *ReadDB) SyncFromWals(ctx context.Context, startWalSeq, endWalSeq string } } if err := insertfunc(walFiles); err != nil { - return "", err + return "", errors.WithStack(err) } return lastWalSeq, nil @@ -248,17 +248,17 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { var err error curWalSeq, err = r.GetCommittedWalSequence(tx) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } lastCommittedStorageWal, _, err := r.dm.LastCommittedStorageWal(ctx) if err != nil { - return err + return errors.WithStack(err) } doFullSync := false @@ -268,7 +268,7 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { } else { ok, err := r.dm.HasOSTWal(curWalSeq) if err != nil { - return err + return errors.WithStack(err) } if !ok { r.log.Warn().Msgf("no wal with seq %q in objectstorage, doing a full sync", curWalSeq) @@ -282,13 +282,13 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { // TODO(sgotti) improve this to avoid doing a full resync curWalSequence, err := sequence.Parse(curWalSeq) if err != nil { - return err + return errors.WithStack(err) } curWalEpoch := curWalSequence.Epoch lastCommittedStorageWalSequence, err := sequence.Parse(lastCommittedStorageWal) if err != nil { - return err + return errors.WithStack(err) } if curWalEpoch != lastCommittedStorageWalSequence.Epoch { r.log.Warn().Msgf("current rdb wal sequence epoch %d different than new wal sequence epoch %d, doing a full sync", curWalEpoch, lastCommittedStorageWalSequence.Epoch) @@ -299,13 +299,13 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { if doFullSync { r.log.Info().Msgf("doing a full sync from dump") if err := r.ResetDB(ctx); err != nil { - return err + return errors.WithStack(err) } var err error curWalSeq, err = r.SyncFromDump(ctx) if err != nil { - return err + return errors.WithStack(err) } } @@ -318,7 +318,7 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { // committedstorage in etcd curWalSeq, err = r.SyncFromWals(ctx, curWalSeq, lastCommittedStorageWal) if err != nil { - return errors.Errorf("failed to sync from wals: %w", err) + return errors.Wrapf(err, "failed to sync from wals") } // Get the first available wal from etcd and check that our current walseq @@ -327,7 +327,7 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { // many new wals are written, the next sync should be faster and able to continue firstAvailableWalData, revision, err := r.dm.FirstAvailableWalData(ctx) if err != nil { - return errors.Errorf("failed to get first available wal data: %w", err) + return errors.Wrapf(err, "failed to get first available wal data") } r.log.Debug().Msgf("firstAvailableWalData: %s", util.Dump(firstAvailableWalData)) r.log.Debug().Msgf("revision: %d", revision) @@ -341,13 +341,13 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { r.log.Info().Msgf("syncing from wals") err = r.rdb.Do(ctx, func(tx *db.Tx) error { if err := r.insertRevision(tx, revision); err != nil { - return err + return errors.WithStack(err) } // use the same revision as previous operation for walElement := range r.dm.ListEtcdWals(ctx, revision) { if walElement.Err != nil { - return walElement.Err + return errors.WithStack(walElement.Err) } if walElement.WalData.WalSequence <= curWalSeq { continue @@ -359,31 +359,31 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { } if err := r.insertCommittedWalSequence(tx, walElement.WalData.WalSequence); err != nil { - return err + return errors.WithStack(err) } r.log.Debug().Msgf("applying wal to db") if err := r.applyWal(tx, walElement.WalData.WalDataFileID); err != nil { - return err + return errors.WithStack(err) } } // sync changegroups, use the same revision of previous operations changeGroupsRevisions, err := r.dm.ListEtcdChangeGroups(ctx, revision) if err != nil { - return err + return errors.WithStack(err) } for changeGroupID, changeGroupRevision := range changeGroupsRevisions { if err := r.insertChangeGroupRevision(tx, changeGroupID, changeGroupRevision); err != nil { - return err + return errors.WithStack(err) } } return nil }) - return err + return errors.WithStack(err) } func (r *ReadDB) Run(ctx context.Context) error { @@ -392,18 +392,18 @@ func (r *ReadDB) Run(ctx context.Context) error { } rdb, err := db.NewDB(db.Sqlite3, filepath.Join(r.dataDir, "db")) if err != nil { - return err + return errors.WithStack(err) } r.rdb = rdb // populate readdb if err := r.rdb.Create(ctx, Stmts); err != nil { - return err + return errors.WithStack(err) } revision, err := r.GetRevision(ctx) if err != nil { - return err + return errors.WithStack(err) } if revision == 0 || !r.Initialized { @@ -491,13 +491,13 @@ func (r *ReadDB) handleEvents(ctx context.Context) error { if errors.Is(err, sql.ErrNoRows) { revision = 0 } else { - return err + return errors.WithStack(err) } } return nil }) if err != nil { - return err + return errors.WithStack(err) } wctx, cancel := context.WithCancel(ctx) @@ -513,7 +513,7 @@ func (r *ReadDB) handleEvents(ctx context.Context) error { r.Initialized = false return nil } - return errors.Errorf("watch error: %w", err) + return errors.Wrapf(err, "watch error") } // a single transaction for every response (every response contains all the @@ -527,19 +527,19 @@ func (r *ReadDB) handleEvents(ctx context.Context) error { // lost from etcd) curWalSeq, err := r.GetCommittedWalSequence(tx) if err != nil { - return err + return errors.WithStack(err) } r.log.Debug().Msgf("curWalSeq: %q", curWalSeq) if curWalSeq != "" && we.WalData != nil { curWalSequence, err := sequence.Parse(curWalSeq) if err != nil { - return err + return errors.WithStack(err) } curWalEpoch := curWalSequence.Epoch weWalSequence, err := sequence.Parse(we.WalData.WalSequence) if err != nil { - return err + return errors.WithStack(err) } r.log.Debug().Msgf("we.WalData.WalSequence: %q", we.WalData.WalSequence) weWalEpoch := weWalSequence.Epoch @@ -550,16 +550,16 @@ func (r *ReadDB) handleEvents(ctx context.Context) error { } if err := r.handleEvent(tx, we); err != nil { - return err + return errors.WithStack(err) } if err := r.insertRevision(tx, we.Revision); err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } } r.log.Info().Msgf("wch closed") @@ -572,7 +572,7 @@ func (r *ReadDB) handleEvent(tx *db.Tx, we *datamanager.WatchElement) error { //key := string(ev.Kv.Key) if err := r.handleWalEvent(tx, we); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -580,7 +580,7 @@ func (r *ReadDB) handleEvent(tx *db.Tx, we *datamanager.WatchElement) error { func (r *ReadDB) handleWalEvent(tx *db.Tx, we *datamanager.WatchElement) error { for cgName, cgRev := range we.ChangeGroupsRevisions { if err := r.insertChangeGroupRevision(tx, cgName, cgRev); err != nil { - return err + return errors.WithStack(err) } } @@ -591,7 +591,7 @@ func (r *ReadDB) handleWalEvent(tx *db.Tx, we *datamanager.WatchElement) error { } if err := r.insertCommittedWalSequence(tx, we.WalData.WalSequence); err != nil { - return err + return errors.WithStack(err) } r.log.Debug().Msgf("applying wal to db") @@ -603,7 +603,7 @@ func (r *ReadDB) handleWalEvent(tx *db.Tx, we *datamanager.WatchElement) error { func (r *ReadDB) applyWal(tx *db.Tx, walDataFileID string) error { walFile, err := r.dm.ReadWalData(walDataFileID) if err != nil { - return errors.Errorf("cannot read wal data file %q: %w", walDataFileID, err) + return errors.Wrapf(err, "cannot read wal data file %q", walDataFileID) } defer walFile.Close() @@ -617,11 +617,11 @@ func (r *ReadDB) applyWal(tx *db.Tx, walDataFileID string) error { break } if err != nil { - return errors.Errorf("failed to decode wal file: %w", err) + return errors.Wrapf(err, "failed to decode wal file") } if err := r.applyAction(tx, action); err != nil { - return err + return errors.WithStack(err) } } @@ -634,35 +634,35 @@ func (r *ReadDB) applyAction(tx *db.Tx, action *datamanager.Action) error { switch types.ConfigType(action.DataType) { case types.ConfigTypeUser: if err := r.insertUser(tx, action.Data); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeOrg: if err := r.insertOrg(tx, action.Data); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeOrgMember: if err := r.insertOrgMember(tx, action.Data); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeProjectGroup: if err := r.insertProjectGroup(tx, action.Data); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeProject: if err := r.insertProject(tx, action.Data); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeRemoteSource: if err := r.insertRemoteSource(tx, action.Data); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeSecret: if err := r.insertSecret(tx, action.Data); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeVariable: if err := r.insertVariable(tx, action.Data); err != nil { - return err + return errors.WithStack(err) } } @@ -671,42 +671,42 @@ func (r *ReadDB) applyAction(tx *db.Tx, action *datamanager.Action) error { case types.ConfigTypeUser: r.log.Debug().Msgf("deleting user with id: %s", action.ID) if err := r.deleteUser(tx, action.ID); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeOrg: r.log.Debug().Msgf("deleting org with id: %s", action.ID) if err := r.deleteOrg(tx, action.ID); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeOrgMember: r.log.Debug().Msgf("deleting orgmember with id: %s", action.ID) if err := r.deleteOrgMember(tx, action.ID); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeProjectGroup: r.log.Debug().Msgf("deleting project group with id: %s", action.ID) if err := r.deleteProjectGroup(tx, action.ID); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeProject: r.log.Debug().Msgf("deleting project with id: %s", action.ID) if err := r.deleteProject(tx, action.ID); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeRemoteSource: r.log.Debug().Msgf("deleting remote source with id: %s", action.ID) if err := r.deleteRemoteSource(tx, action.ID); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeSecret: r.log.Debug().Msgf("deleting secret with id: %s", action.ID) if err := r.deleteSecret(tx, action.ID); err != nil { - return err + return errors.WithStack(err) } case types.ConfigTypeVariable: r.log.Debug().Msgf("deleting variable with id: %s", action.ID) if err := r.deleteVariable(tx, action.ID); err != nil { - return err + return errors.WithStack(err) } } } @@ -715,21 +715,21 @@ func (r *ReadDB) applyAction(tx *db.Tx, action *datamanager.Action) error { } func (r *ReadDB) Do(ctx context.Context, f func(tx *db.Tx) error) error { - return r.rdb.Do(ctx, f) + return errors.WithStack(r.rdb.Do(ctx, f)) } func (r *ReadDB) insertRevision(tx *db.Tx, revision int64) error { // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from revision"); err != nil { - return errors.Errorf("failed to delete revision: %w", err) + return errors.Wrapf(err, "failed to delete revision") } // TODO(sgotti) go database/sql and mattn/sqlite3 don't support uint64 types... q, args, err := revisionInsert.Values(revision).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -740,9 +740,9 @@ func (r *ReadDB) GetRevision(ctx context.Context) (int64, error) { err := r.rdb.Do(ctx, func(tx *db.Tx) error { var err error revision, err = r.getRevision(tx) - return err + return errors.WithStack(err) }) - return revision, err + return revision, errors.WithStack(err) } func (r *ReadDB) getRevision(tx *db.Tx) (int64, error) { @@ -751,28 +751,28 @@ func (r *ReadDB) getRevision(tx *db.Tx) (int64, error) { q, args, err := revisionSelect.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return 0, errors.Errorf("failed to build query: %w", err) + return 0, errors.Wrapf(err, "failed to build query") } err = tx.QueryRow(q, args...).Scan(&revision) if errors.Is(err, sql.ErrNoRows) { return 0, nil } - return revision, err + return revision, errors.WithStack(err) } func (r *ReadDB) insertCommittedWalSequence(tx *db.Tx, seq string) error { r.log.Debug().Msgf("insert seq: %s", seq) // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from committedwalsequence"); err != nil { - return errors.Errorf("failed to delete committedwalsequence: %w", err) + return errors.Wrapf(err, "failed to delete committedwalsequence") } q, args, err := committedwalsequenceInsert.Values(seq).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -783,14 +783,14 @@ func (r *ReadDB) GetCommittedWalSequence(tx *db.Tx) (string, error) { q, args, err := committedwalsequenceSelect.OrderBy("seq").Limit(1).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return "", errors.Errorf("failed to build query: %w", err) + return "", errors.Wrapf(err, "failed to build query") } err = tx.QueryRow(q, args...).Scan(&seq) if errors.Is(err, sql.ErrNoRows) { return "", nil } - return seq, err + return seq, errors.WithStack(err) } func (r *ReadDB) insertChangeGroupRevision(tx *db.Tx, changegroup string, revision int64) error { @@ -798,16 +798,16 @@ func (r *ReadDB) insertChangeGroupRevision(tx *db.Tx, changegroup string, revisi // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from changegrouprevision where id = $1", changegroup); err != nil { - return errors.Errorf("failed to delete run: %w", err) + return errors.Wrapf(err, "failed to delete run") } // insert only if revision > 0 if revision > 0 { q, args, err := changegrouprevisionInsert.Values(changegroup, revision).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } } return nil @@ -818,16 +818,16 @@ func (r *ReadDB) GetChangeGroupsUpdateTokens(tx *db.Tx, groups []string) (*datam q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } cgr, err := fetchChangeGroupsRevision(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } revision, err := r.getRevision(tx) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // for non existing changegroups use a changegroup with revision = 0 @@ -843,7 +843,7 @@ func (r *ReadDB) GetChangeGroupsUpdateTokens(tx *db.Tx, groups []string) (*datam func fetchChangeGroupsRevision(tx *db.Tx, q string, args ...interface{}) (map[string]int64, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer rows.Close() return scanChangeGroupsRevision(rows) @@ -857,12 +857,12 @@ func scanChangeGroupsRevision(rows *sql.Rows) (map[string]int64, error) { revision int64 ) if err := rows.Scan(&id, &revision); err != nil { - return nil, errors.Errorf("failed to scan rows: %w", err) + return nil, errors.Wrapf(err, "failed to scan rows") } changegroups[id] = revision } if err := rows.Err(); err != nil { - return nil, err + return nil, errors.WithStack(err) } return changegroups, nil } diff --git a/internal/services/configstore/readdb/remotesource.go b/internal/services/configstore/readdb/remotesource.go index 63a25a2..da71fc1 100644 --- a/internal/services/configstore/readdb/remotesource.go +++ b/internal/services/configstore/readdb/remotesource.go @@ -20,12 +20,12 @@ import ( "encoding/json" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/configstore/common" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" sq "github.com/Masterminds/squirrel" - errors "golang.org/x/xerrors" ) var ( @@ -36,18 +36,18 @@ var ( func (r *ReadDB) insertRemoteSource(tx *db.Tx, data []byte) error { remoteSource := types.RemoteSource{} if err := json.Unmarshal(data, &remoteSource); err != nil { - return errors.Errorf("failed to unmarshal remotesource: %w", err) + return errors.Wrapf(err, "failed to unmarshal remotesource") } // poor man insert or update... if err := r.deleteRemoteSource(tx, remoteSource.ID); err != nil { - return err + return errors.WithStack(err) } q, args, err := remotesourceInsert.Values(remoteSource.ID, remoteSource.Name, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert remotesource: %w", err) + return errors.Wrapf(err, "failed to insert remotesource") } return nil @@ -56,7 +56,7 @@ func (r *ReadDB) insertRemoteSource(tx *db.Tx, data []byte) error { func (r *ReadDB) deleteRemoteSource(tx *db.Tx, id string) error { // poor man insert or update... if _, err := tx.Exec("delete from remotesource where id = $1", id); err != nil { - return errors.Errorf("failed to delete remotesource: %w", err) + return errors.Wrapf(err, "failed to delete remotesource") } return nil } @@ -64,7 +64,7 @@ func (r *ReadDB) deleteRemoteSource(tx *db.Tx, id string) error { func (r *ReadDB) GetRemoteSource(tx *db.Tx, rsRef string) (*types.RemoteSource, error) { refType, err := common.ParseNameRef(rsRef) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var rs *types.RemoteSource @@ -74,19 +74,19 @@ func (r *ReadDB) GetRemoteSource(tx *db.Tx, rsRef string) (*types.RemoteSource, case common.RefTypeName: rs, err = r.GetRemoteSourceByName(tx, rsRef) } - return rs, err + return rs, errors.WithStack(err) } func (r *ReadDB) GetRemoteSourceByID(tx *db.Tx, remoteSourceID string) (*types.RemoteSource, error) { q, args, err := remotesourceSelect.Where(sq.Eq{"id": remoteSourceID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } remoteSources, _, err := fetchRemoteSources(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(remoteSources) > 1 { return nil, errors.Errorf("too many rows returned") @@ -101,12 +101,12 @@ func (r *ReadDB) GetRemoteSourceByName(tx *db.Tx, name string) (*types.RemoteSou q, args, err := remotesourceSelect.Where(sq.Eq{"name": name}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } remoteSources, _, err := fetchRemoteSources(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(remoteSources) > 1 { return nil, errors.Errorf("too many rows returned") @@ -147,25 +147,25 @@ func (r *ReadDB) GetRemoteSources(ctx context.Context, startRemoteSourceName str q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } err = r.rdb.Do(ctx, func(tx *db.Tx) error { rows, err := tx.Query(q, args...) if err != nil { - return err + return errors.WithStack(err) } remoteSources, _, err = scanRemoteSources(rows) - return err + return errors.WithStack(err) }) - return remoteSources, err + return remoteSources, errors.WithStack(err) } func fetchRemoteSources(tx *db.Tx, q string, args ...interface{}) ([]*types.RemoteSource, []string, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } defer rows.Close() return scanRemoteSources(rows) @@ -175,12 +175,12 @@ func scanRemoteSource(rows *sql.Rows, additionalFields ...interface{}) (*types.R var id string var data []byte if err := rows.Scan(&id, &data); err != nil { - return nil, "", errors.Errorf("failed to scan rows: %w", err) + return nil, "", errors.Wrapf(err, "failed to scan rows") } remoteSource := types.RemoteSource{} if len(data) > 0 { if err := json.Unmarshal(data, &remoteSource); err != nil { - return nil, "", errors.Errorf("failed to unmarshal remotesource: %w", err) + return nil, "", errors.Wrapf(err, "failed to unmarshal remotesource") } } @@ -194,13 +194,13 @@ func scanRemoteSources(rows *sql.Rows) ([]*types.RemoteSource, []string, error) p, id, err := scanRemoteSource(rows) if err != nil { rows.Close() - return nil, nil, err + return nil, nil, errors.WithStack(err) } remoteSources = append(remoteSources, p) ids = append(ids, id) } if err := rows.Err(); err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } return remoteSources, ids, nil } diff --git a/internal/services/configstore/readdb/resolve.go b/internal/services/configstore/readdb/resolve.go index 5fd3ef3..7fea923 100644 --- a/internal/services/configstore/readdb/resolve.go +++ b/internal/services/configstore/readdb/resolve.go @@ -18,42 +18,70 @@ import ( "path" "agola.io/agola/internal/db" - "agola.io/agola/services/configstore/types" + "agola.io/agola/internal/errors" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/util" + "agola.io/agola/services/configstore/types" ) +func (r *ReadDB) ResolveConfigID(tx *db.Tx, configType types.ConfigType, ref string) (string, error) { + switch configType { + case types.ConfigTypeProjectGroup: + group, err := r.GetProjectGroup(tx, ref) + if err != nil { + return "", errors.WithStack(err) + } + if group == nil { + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("group with ref %q doesn't exists", ref)) + } + return group.ID, nil + + case types.ConfigTypeProject: + project, err := r.GetProject(tx, ref) + if err != nil { + return "", errors.WithStack(err) + } + if project == nil { + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with ref %q doesn't exists", ref)) + } + return project.ID, nil + + default: + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("unknown config type %q", configType)) + } +} + func (r *ReadDB) GetPath(tx *db.Tx, configType types.ConfigType, id string) (string, error) { var p string switch configType { case types.ConfigTypeProjectGroup: projectGroup, err := r.GetProjectGroup(tx, id) if err != nil { - return "", err + return "", errors.WithStack(err) } if projectGroup == nil { return "", errors.Errorf("projectgroup with id %q doesn't exist", id) } p, err = r.GetProjectGroupPath(tx, projectGroup) if err != nil { - return "", err + return "", errors.WithStack(err) } case types.ConfigTypeProject: project, err := r.GetProject(tx, id) if err != nil { - return "", err + return "", errors.WithStack(err) } if project == nil { return "", errors.Errorf("project with id %q doesn't exist", id) } p, err = r.GetProjectPath(tx, project) if err != nil { - return "", err + return "", errors.WithStack(err) } case types.ConfigTypeOrg: org, err := r.GetOrg(tx, id) if err != nil { - return "", errors.Errorf("failed to get org %q: %w", id, err) + return "", errors.Wrapf(err, "failed to get org %q", id) } if org == nil { return "", errors.Errorf("cannot find org with id %q", id) @@ -62,7 +90,7 @@ func (r *ReadDB) GetPath(tx *db.Tx, configType types.ConfigType, id string) (str case types.ConfigTypeUser: user, err := r.GetUser(tx, id) if err != nil { - return "", errors.Errorf("failed to get user %q: %w", id, err) + return "", errors.Wrapf(err, "failed to get user %q", id) } if user == nil { return "", errors.Errorf("cannot find user with id %q", id) diff --git a/internal/services/configstore/readdb/secret.go b/internal/services/configstore/readdb/secret.go index e0efaea..bd6a05e 100644 --- a/internal/services/configstore/readdb/secret.go +++ b/internal/services/configstore/readdb/secret.go @@ -19,11 +19,11 @@ import ( "encoding/json" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" sq "github.com/Masterminds/squirrel" - errors "golang.org/x/xerrors" ) var ( @@ -34,18 +34,18 @@ var ( func (r *ReadDB) insertSecret(tx *db.Tx, data []byte) error { secret := types.Secret{} if err := json.Unmarshal(data, &secret); err != nil { - return errors.Errorf("failed to unmarshal secret: %w", err) + return errors.Wrapf(err, "failed to unmarshal secret") } // poor man insert or update... if err := r.deleteSecret(tx, secret.ID); err != nil { - return err + return errors.WithStack(err) } q, args, err := secretInsert.Values(secret.ID, secret.Name, secret.Parent.ID, secret.Parent.Type, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert secret: %w", err) + return errors.Wrapf(err, "failed to insert secret") } return nil @@ -54,7 +54,7 @@ func (r *ReadDB) insertSecret(tx *db.Tx, data []byte) error { func (r *ReadDB) deleteSecret(tx *db.Tx, id string) error { // poor man insert or update... if _, err := tx.Exec("delete from secret where id = $1", id); err != nil { - return errors.Errorf("failed to delete secret: %w", err) + return errors.Wrapf(err, "failed to delete secret") } return nil } @@ -63,12 +63,12 @@ func (r *ReadDB) GetSecretByID(tx *db.Tx, secretID string) (*types.Secret, error q, args, err := secretSelect.Where(sq.Eq{"id": secretID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } secrets, _, err := fetchSecrets(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(secrets) > 1 { return nil, errors.Errorf("too many rows returned") @@ -83,12 +83,12 @@ func (r *ReadDB) GetSecretByName(tx *db.Tx, parentID, name string) (*types.Secre q, args, err := secretSelect.Where(sq.Eq{"parentid": parentID, "name": name}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } secrets, _, err := fetchSecrets(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(secrets) > 1 { return nil, errors.Errorf("too many rows returned") @@ -103,18 +103,18 @@ func (r *ReadDB) GetSecrets(tx *db.Tx, parentID string) ([]*types.Secret, error) q, args, err := secretSelect.Where(sq.Eq{"parentid": parentID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } secrets, _, err := fetchSecrets(tx, q, args...) - return secrets, err + return secrets, errors.WithStack(err) } func (r *ReadDB) GetSecretTree(tx *db.Tx, parentType types.ConfigType, parentID, name string) (*types.Secret, error) { for parentType == types.ConfigTypeProjectGroup || parentType == types.ConfigTypeProject { secret, err := r.GetSecretByName(tx, parentID, name) if err != nil { - return nil, errors.Errorf("failed to get secret with name %q: %w", name, err) + return nil, errors.Wrapf(err, "failed to get secret with name %q", name) } if secret != nil { return secret, nil @@ -124,7 +124,7 @@ func (r *ReadDB) GetSecretTree(tx *db.Tx, parentType types.ConfigType, parentID, case types.ConfigTypeProjectGroup: projectGroup, err := r.GetProjectGroup(tx, parentID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if projectGroup == nil { return nil, errors.Errorf("projectgroup with id %q doesn't exist", parentID) @@ -134,7 +134,7 @@ func (r *ReadDB) GetSecretTree(tx *db.Tx, parentType types.ConfigType, parentID, case types.ConfigTypeProject: project, err := r.GetProject(tx, parentID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if project == nil { return nil, errors.Errorf("project with id %q doesn't exist", parentID) @@ -153,7 +153,7 @@ func (r *ReadDB) GetSecretsTree(tx *db.Tx, parentType types.ConfigType, parentID for parentType == types.ConfigTypeProjectGroup || parentType == types.ConfigTypeProject { secrets, err := r.GetSecrets(tx, parentID) if err != nil { - return nil, errors.Errorf("failed to get secrets for %s %q: %w", parentType, parentID, err) + return nil, errors.Wrapf(err, "failed to get secrets for %s %q", parentType, parentID) } allSecrets = append(allSecrets, secrets...) @@ -161,7 +161,7 @@ func (r *ReadDB) GetSecretsTree(tx *db.Tx, parentType types.ConfigType, parentID case types.ConfigTypeProjectGroup: projectGroup, err := r.GetProjectGroup(tx, parentID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if projectGroup == nil { return nil, errors.Errorf("projectgroup with id %q doesn't exist", parentID) @@ -171,7 +171,7 @@ func (r *ReadDB) GetSecretsTree(tx *db.Tx, parentType types.ConfigType, parentID case types.ConfigTypeProject: project, err := r.GetProject(tx, parentID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if project == nil { return nil, errors.Errorf("project with id %q doesn't exist", parentID) @@ -187,7 +187,7 @@ func (r *ReadDB) GetSecretsTree(tx *db.Tx, parentType types.ConfigType, parentID func fetchSecrets(tx *db.Tx, q string, args ...interface{}) ([]*types.Secret, []string, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } defer rows.Close() return scanSecrets(rows) @@ -197,12 +197,12 @@ func scanSecret(rows *sql.Rows, additionalFields ...interface{}) (*types.Secret, var id string var data []byte if err := rows.Scan(&id, &data); err != nil { - return nil, "", errors.Errorf("failed to scan rows: %w", err) + return nil, "", errors.Wrapf(err, "failed to scan rows") } secret := types.Secret{} if len(data) > 0 { if err := json.Unmarshal(data, &secret); err != nil { - return nil, "", errors.Errorf("failed to unmarshal secret: %w", err) + return nil, "", errors.Wrapf(err, "failed to unmarshal secret") } } @@ -216,13 +216,13 @@ func scanSecrets(rows *sql.Rows) ([]*types.Secret, []string, error) { p, id, err := scanSecret(rows) if err != nil { rows.Close() - return nil, nil, err + return nil, nil, errors.WithStack(err) } secrets = append(secrets, p) ids = append(ids, id) } if err := rows.Err(); err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } return secrets, ids, nil } diff --git a/internal/services/configstore/readdb/user.go b/internal/services/configstore/readdb/user.go index 11f92a5..667c511 100644 --- a/internal/services/configstore/readdb/user.go +++ b/internal/services/configstore/readdb/user.go @@ -19,12 +19,12 @@ import ( "encoding/json" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/configstore/common" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" sq "github.com/Masterminds/squirrel" - errors "golang.org/x/xerrors" ) var ( @@ -44,46 +44,46 @@ var ( func (r *ReadDB) insertUser(tx *db.Tx, data []byte) error { user := types.User{} if err := json.Unmarshal(data, &user); err != nil { - return errors.Errorf("failed to unmarshal user: %w", err) + return errors.Wrapf(err, "failed to unmarshal user") } r.log.Debug().Msgf("inserting user: %s", util.Dump(user)) // poor man insert or update... if err := r.deleteUser(tx, user.ID); err != nil { - return err + return errors.WithStack(err) } q, args, err := userInsert.Values(user.ID, user.Name, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err := tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert user: %w", err) + return errors.Wrapf(err, "failed to insert user") } // insert linkedaccounts_user for _, la := range user.LinkedAccounts { if err := r.deleteUserLinkedAccount(tx, la.ID); err != nil { - return err + return errors.WithStack(err) } q, args, err = linkedaccountuserInsert.Values(la.ID, la.RemoteSourceID, user.ID, la.RemoteUserID).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err := tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert user: %w", err) + return errors.Wrapf(err, "failed to insert user") } } // insert user_token for _, tokenValue := range user.Tokens { r.log.Debug().Msgf("inserting user token: %s", tokenValue) if err := r.deleteUserToken(tx, tokenValue); err != nil { - return err + return errors.WithStack(err) } q, args, err = usertokenInsert.Values(tokenValue, user.ID).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err := tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert user: %w", err) + return errors.Wrapf(err, "failed to insert user") } } @@ -93,17 +93,17 @@ func (r *ReadDB) insertUser(tx *db.Tx, data []byte) error { func (r *ReadDB) deleteUser(tx *db.Tx, userID string) error { // delete user linked accounts if err := r.deleteUserLinkedAccounts(tx, userID); err != nil { - return errors.Errorf("failed to delete user linked accounts: %w", err) + return errors.Wrapf(err, "failed to delete user linked accounts") } // delete user tokens if _, err := tx.Exec("delete from user_token where userid = $1", userID); err != nil { - return errors.Errorf("failed to delete usertokens: %w", err) + return errors.Wrapf(err, "failed to delete usertokens") } // poor man insert or update... if _, err := tx.Exec("delete from user where id = $1", userID); err != nil { - return errors.Errorf("failed to delete user: %w", err) + return errors.Wrapf(err, "failed to delete user") } return nil @@ -112,10 +112,10 @@ func (r *ReadDB) deleteUser(tx *db.Tx, userID string) error { func (r *ReadDB) deleteUserLinkedAccounts(tx *db.Tx, userID string) error { // poor man insert or update... if _, err := tx.Exec("delete from linkedaccount_user where userid = $1", userID); err != nil { - return errors.Errorf("failed to delete linked account: %w", err) + return errors.Wrapf(err, "failed to delete linked account") } if _, err := tx.Exec("delete from linkedaccount_project where id = $1", userID); err != nil { - return errors.Errorf("failed to delete linked account: %w", err) + return errors.Wrapf(err, "failed to delete linked account") } return nil } @@ -123,10 +123,10 @@ func (r *ReadDB) deleteUserLinkedAccounts(tx *db.Tx, userID string) error { func (r *ReadDB) deleteUserLinkedAccount(tx *db.Tx, id string) error { // poor man insert or update... if _, err := tx.Exec("delete from linkedaccount_user where id = $1", id); err != nil { - return errors.Errorf("failed to delete linked account: %w", err) + return errors.Wrapf(err, "failed to delete linked account") } if _, err := tx.Exec("delete from linkedaccount_project where id = $1", id); err != nil { - return errors.Errorf("failed to delete linked account: %w", err) + return errors.Wrapf(err, "failed to delete linked account") } return nil } @@ -134,7 +134,7 @@ func (r *ReadDB) deleteUserLinkedAccount(tx *db.Tx, id string) error { func (r *ReadDB) deleteUserToken(tx *db.Tx, tokenValue string) error { // poor man insert or update... if _, err := tx.Exec("delete from user_token where tokenvalue = $1", tokenValue); err != nil { - return errors.Errorf("failed to delete user_token: %w", err) + return errors.Wrapf(err, "failed to delete user_token") } return nil } @@ -142,7 +142,7 @@ func (r *ReadDB) deleteUserToken(tx *db.Tx, tokenValue string) error { func (r *ReadDB) GetUser(tx *db.Tx, userRef string) (*types.User, error) { refType, err := common.ParseNameRef(userRef) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var user *types.User @@ -152,19 +152,19 @@ func (r *ReadDB) GetUser(tx *db.Tx, userRef string) (*types.User, error) { case common.RefTypeName: user, err = r.GetUserByName(tx, userRef) } - return user, err + return user, errors.WithStack(err) } func (r *ReadDB) GetUserByID(tx *db.Tx, userID string) (*types.User, error) { q, args, err := userSelect.Where(sq.Eq{"id": userID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } users, _, err := fetchUsers(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(users) > 1 { return nil, errors.Errorf("too many rows returned") @@ -179,12 +179,12 @@ func (r *ReadDB) GetUserByName(tx *db.Tx, name string) (*types.User, error) { q, args, err := userSelect.Where(sq.Eq{"name": name}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } users, _, err := fetchUsers(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(users) > 1 { return nil, errors.Errorf("too many rows returned") @@ -202,12 +202,12 @@ func (r *ReadDB) GetUserByTokenValue(tx *db.Tx, tokenValue string) (*types.User, q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } users, _, err := fetchUsers(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(users) > 1 { return nil, errors.Errorf("too many rows returned") @@ -225,12 +225,12 @@ func (r *ReadDB) GetUserByLinkedAccount(tx *db.Tx, linkedAccountID string) (*typ q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } users, _, err := fetchUsers(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(users) > 1 { return nil, errors.Errorf("too many rows returned") @@ -248,12 +248,12 @@ func (r *ReadDB) GetUserByLinkedAccountRemoteUserIDandSource(tx *db.Tx, remoteUs q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } users, _, err := fetchUsers(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(users) > 1 { return nil, errors.Errorf("too many rows returned") @@ -294,22 +294,22 @@ func (r *ReadDB) GetUsers(tx *db.Tx, startUserName string, limit int, asc bool) q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } rows, err := tx.Query(q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } users, _, err = scanUsers(rows) - return users, err + return users, errors.WithStack(err) } func fetchUsers(tx *db.Tx, q string, args ...interface{}) ([]*types.User, []string, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } defer rows.Close() return scanUsers(rows) @@ -319,12 +319,12 @@ func scanUser(rows *sql.Rows, additionalFields ...interface{}) (*types.User, str var id string var data []byte if err := rows.Scan(&id, &data); err != nil { - return nil, "", errors.Errorf("failed to scan rows: %w", err) + return nil, "", errors.Wrapf(err, "failed to scan rows") } user := types.User{} if len(data) > 0 { if err := json.Unmarshal(data, &user); err != nil { - return nil, "", errors.Errorf("failed to unmarshal user: %w", err) + return nil, "", errors.Wrapf(err, "failed to unmarshal user") } } @@ -338,13 +338,13 @@ func scanUsers(rows *sql.Rows) ([]*types.User, []string, error) { p, id, err := scanUser(rows) if err != nil { rows.Close() - return nil, nil, err + return nil, nil, errors.WithStack(err) } users = append(users, p) ids = append(ids, id) } if err := rows.Err(); err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } return users, ids, nil } diff --git a/internal/services/configstore/readdb/variable.go b/internal/services/configstore/readdb/variable.go index 87cf68d..f79f4c7 100644 --- a/internal/services/configstore/readdb/variable.go +++ b/internal/services/configstore/readdb/variable.go @@ -19,11 +19,11 @@ import ( "encoding/json" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" sq "github.com/Masterminds/squirrel" - errors "golang.org/x/xerrors" ) var ( @@ -34,18 +34,18 @@ var ( func (r *ReadDB) insertVariable(tx *db.Tx, data []byte) error { variable := types.Variable{} if err := json.Unmarshal(data, &variable); err != nil { - return errors.Errorf("failed to unmarshal variable: %w", err) + return errors.Wrapf(err, "failed to unmarshal variable") } // poor man insert or update... if err := r.deleteVariable(tx, variable.ID); err != nil { - return err + return errors.WithStack(err) } q, args, err := variableInsert.Values(variable.ID, variable.Name, variable.Parent.ID, variable.Parent.Type, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return errors.Errorf("failed to insert variable: %w", err) + return errors.Wrapf(err, "failed to insert variable") } return nil @@ -54,7 +54,7 @@ func (r *ReadDB) insertVariable(tx *db.Tx, data []byte) error { func (r *ReadDB) deleteVariable(tx *db.Tx, id string) error { // poor man insert or update... if _, err := tx.Exec("delete from variable where id = $1", id); err != nil { - return errors.Errorf("failed to delete variable: %w", err) + return errors.Wrapf(err, "failed to delete variable") } return nil } @@ -63,12 +63,12 @@ func (r *ReadDB) GetVariableByID(tx *db.Tx, variableID string) (*types.Variable, q, args, err := variableSelect.Where(sq.Eq{"id": variableID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } variables, _, err := fetchVariables(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(variables) > 1 { return nil, errors.Errorf("too many rows returned") @@ -83,12 +83,12 @@ func (r *ReadDB) GetVariableByName(tx *db.Tx, parentID, name string) (*types.Var q, args, err := variableSelect.Where(sq.Eq{"parentid": parentID, "name": name}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } variables, _, err := fetchVariables(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(variables) > 1 { return nil, errors.Errorf("too many rows returned") @@ -103,11 +103,11 @@ func (r *ReadDB) GetVariables(tx *db.Tx, parentID string) ([]*types.Variable, er q, args, err := variableSelect.Where(sq.Eq{"parentid": parentID}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } variables, _, err := fetchVariables(tx, q, args...) - return variables, err + return variables, errors.WithStack(err) } func (r *ReadDB) GetVariablesTree(tx *db.Tx, parentType types.ConfigType, parentID string) ([]*types.Variable, error) { @@ -116,7 +116,7 @@ func (r *ReadDB) GetVariablesTree(tx *db.Tx, parentType types.ConfigType, parent for parentType == types.ConfigTypeProjectGroup || parentType == types.ConfigTypeProject { vars, err := r.GetVariables(tx, parentID) if err != nil { - return nil, errors.Errorf("failed to get variables for %s %q: %w", parentType, parentID, err) + return nil, errors.Wrapf(err, "failed to get variables for %s %q", parentType, parentID) } allVariables = append(allVariables, vars...) @@ -124,7 +124,7 @@ func (r *ReadDB) GetVariablesTree(tx *db.Tx, parentType types.ConfigType, parent case types.ConfigTypeProjectGroup: projectGroup, err := r.GetProjectGroup(tx, parentID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if projectGroup == nil { return nil, errors.Errorf("projectgroup with id %q doesn't exist", parentID) @@ -134,7 +134,7 @@ func (r *ReadDB) GetVariablesTree(tx *db.Tx, parentType types.ConfigType, parent case types.ConfigTypeProject: project, err := r.GetProject(tx, parentID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if project == nil { return nil, errors.Errorf("project with id %q doesn't exist", parentID) @@ -150,7 +150,7 @@ func (r *ReadDB) GetVariablesTree(tx *db.Tx, parentType types.ConfigType, parent func fetchVariables(tx *db.Tx, q string, args ...interface{}) ([]*types.Variable, []string, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } defer rows.Close() return scanVariables(rows) @@ -160,12 +160,12 @@ func scanVariable(rows *sql.Rows, additionalFields ...interface{}) (*types.Varia var id string var data []byte if err := rows.Scan(&id, &data); err != nil { - return nil, "", errors.Errorf("failed to scan rows: %w", err) + return nil, "", errors.Wrapf(err, "failed to scan rows") } variable := types.Variable{} if len(data) > 0 { if err := json.Unmarshal(data, &variable); err != nil { - return nil, "", errors.Errorf("failed to unmarshal variable: %w", err) + return nil, "", errors.Wrapf(err, "failed to unmarshal variable") } } @@ -179,13 +179,13 @@ func scanVariables(rows *sql.Rows) ([]*types.Variable, []string, error) { p, id, err := scanVariable(rows) if err != nil { rows.Close() - return nil, nil, err + return nil, nil, errors.WithStack(err) } variables = append(variables, p) ids = append(ids, id) } if err := rows.Err(); err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } return variables, ids, nil } diff --git a/internal/services/executor/api.go b/internal/services/executor/api.go index 5063091..b5c8986 100644 --- a/internal/services/executor/api.go +++ b/internal/services/executor/api.go @@ -23,9 +23,9 @@ import ( "strconv" "time" + "agola.io/agola/internal/errors" "agola.io/agola/services/runservice/types" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) type taskSubmissionHandler struct { @@ -119,7 +119,7 @@ func (h *logsHandler) readLogs(taskID string, setup bool, step int, logPath stri } else { http.Error(w, "", http.StatusInternalServerError) } - return err + return errors.WithStack(err) } defer f.Close() @@ -132,7 +132,7 @@ func (h *logsHandler) readLogs(taskID string, setup bool, step int, logPath stri if !follow { fi, err := f.Stat() if err != nil { - return err + return errors.WithStack(err) } w.Header().Set("Content-Length", strconv.FormatInt(fi.Size(), 10)) } @@ -157,11 +157,11 @@ func (h *logsHandler) readLogs(taskID string, setup bool, step int, logPath stri n, err := f.Read(buf) if err != nil { if err != io.EOF { - return err + return errors.WithStack(err) } if !flushstop && follow { if _, err := f.Seek(-int64(n), io.SeekCurrent); err != nil { - return errors.Errorf("failed to seek in log file %q: %w", logPath, err) + return errors.Wrapf(err, "failed to seek in log file %q", logPath) } // check if the step is finished, if so flush until EOF and stop rt, ok := h.e.runningTasks.get(taskID) @@ -182,7 +182,7 @@ func (h *logsHandler) readLogs(taskID string, setup bool, step int, logPath stri } } if _, err := w.Write(buf[:n]); err != nil { - return err + return errors.WithStack(err) } if flusher != nil { flusher.Flush() @@ -234,12 +234,12 @@ func (h *archivesHandler) readArchive(taskID string, step int, w http.ResponseWr f, err := os.Open(archivePath) if err != nil { - return err + return errors.WithStack(err) } defer f.Close() fi, err := f.Stat() if err != nil { - return err + return errors.WithStack(err) } w.Header().Set("Content-Length", strconv.FormatInt(fi.Size(), 10)) @@ -247,5 +247,5 @@ func (h *archivesHandler) readArchive(taskID string, step int, w http.ResponseWr br := bufio.NewReader(f) _, err = io.Copy(w, br) - return err + return errors.WithStack(err) } diff --git a/internal/services/executor/driver/docker.go b/internal/services/executor/driver/docker.go index 9f5c8a9..ee87bfd 100644 --- a/internal/services/executor/driver/docker.go +++ b/internal/services/executor/driver/docker.go @@ -28,9 +28,9 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/executor/registry" "agola.io/agola/services/types" - errors "golang.org/x/xerrors" dockertypes "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -56,7 +56,7 @@ type DockerDriver struct { func NewDockerDriver(log zerolog.Logger, executorID, toolboxPath, initImage string, initDockerConfig *registry.DockerConfig) (*DockerDriver, error) { cli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.26")) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &DockerDriver{ @@ -76,7 +76,7 @@ func (d *DockerDriver) Setup(ctx context.Context) error { func (d *DockerDriver) createToolboxVolume(ctx context.Context, podID string, out io.Writer) (*dockertypes.Volume, error) { if err := d.fetchImage(ctx, d.initImage, false, d.initDockerConfig, out); err != nil { - return nil, err + return nil, errors.WithStack(err) } labels := map[string]string{} @@ -85,7 +85,7 @@ func (d *DockerDriver) createToolboxVolume(ctx context.Context, podID string, ou labels[podIDKey] = podID toolboxVol, err := d.client.VolumeCreate(ctx, volume.VolumeCreateBody{Driver: "local", Labels: labels}) if err != nil { - return nil, err + return nil, errors.WithStack(err) } resp, err := d.client.ContainerCreate(ctx, &container.Config{ @@ -96,28 +96,28 @@ func (d *DockerDriver) createToolboxVolume(ctx context.Context, podID string, ou Binds: []string{fmt.Sprintf("%s:%s", toolboxVol.Name, "/tmp/agola")}, }, nil, "") if err != nil { - return nil, err + return nil, errors.WithStack(err) } containerID := resp.ID if err := d.client.ContainerStart(ctx, containerID, dockertypes.ContainerStartOptions{}); err != nil { - return nil, err + return nil, errors.WithStack(err) } toolboxExecPath, err := toolboxExecPath(d.toolboxPath, d.arch) if err != nil { - return nil, errors.Errorf("failed to get toolbox path for arch %q: %w", d.arch, err) + return nil, errors.Wrapf(err, "failed to get toolbox path for arch %q", d.arch) } srcInfo, err := archive.CopyInfoSourcePath(toolboxExecPath, false) if err != nil { - return nil, err + return nil, errors.WithStack(err) } srcInfo.RebaseName = "agola-toolbox" srcArchive, err := archive.TarResource(srcInfo) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer srcArchive.Close() @@ -127,7 +127,7 @@ func (d *DockerDriver) createToolboxVolume(ctx context.Context, podID string, ou } if err := d.client.CopyToContainer(ctx, containerID, "/tmp/agola", srcArchive, options); err != nil { - return nil, err + return nil, errors.WithStack(err) } // ignore remove error @@ -148,14 +148,14 @@ func (d *DockerDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io. toolboxVol, err := d.createToolboxVolume(ctx, podConfig.ID, out) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var mainContainerID string for cindex := range podConfig.Containers { resp, err := d.createContainer(ctx, cindex, podConfig, mainContainerID, toolboxVol, out) if err != nil { - return nil, err + return nil, errors.WithStack(err) } containerID := resp.ID @@ -165,7 +165,7 @@ func (d *DockerDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io. } if err := d.client.ContainerStart(ctx, containerID, dockertypes.ContainerStartOptions{}); err != nil { - return nil, err + return nil, errors.WithStack(err) } } @@ -184,7 +184,7 @@ func (d *DockerDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io. Filters: args, }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(containers) == 0 { return nil, errors.Errorf("no container with labels %s", searchLabels) @@ -236,7 +236,7 @@ func (d *DockerDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io. func (d *DockerDriver) fetchImage(ctx context.Context, image string, alwaysFetch bool, registryConfig *registry.DockerConfig, out io.Writer) error { regName, err := registry.GetRegistry(image) if err != nil { - return err + return errors.WithStack(err) } var registryAuth registry.DockerConfigAuth if registryConfig != nil { @@ -246,20 +246,20 @@ func (d *DockerDriver) fetchImage(ctx context.Context, image string, alwaysFetch } buf, err := json.Marshal(registryAuth) if err != nil { - return err + return errors.WithStack(err) } registryAuthEnc := base64.URLEncoding.EncodeToString(buf) tag, err := registry.GetImageTagOrDigest(image) if err != nil { - return err + return errors.WithStack(err) } args := filters.NewArgs() args.Add("reference", image) img, err := d.client.ImageList(ctx, dockertypes.ImageListOptions{Filters: args}) if err != nil { - return err + return errors.WithStack(err) } exists := len(img) > 0 @@ -267,11 +267,11 @@ func (d *DockerDriver) fetchImage(ctx context.Context, image string, alwaysFetch if alwaysFetch || tag == "latest" || !exists { reader, err := d.client.ImagePull(ctx, image, dockertypes.ImagePullOptions{RegistryAuth: registryAuthEnc}) if err != nil { - return err + return errors.WithStack(err) } _, err = io.Copy(out, reader) - return err + return errors.WithStack(err) } return nil @@ -283,7 +283,7 @@ func (d *DockerDriver) createContainer(ctx context.Context, index int, podConfig // by default always try to pull the image so we are sure only authorized users can fetch them // see https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages if err := d.fetchImage(ctx, containerConfig.Image, true, podConfig.DockerConfig, out); err != nil { - return nil, err + return nil, errors.WithStack(err) } labels := map[string]string{} @@ -340,7 +340,7 @@ func (d *DockerDriver) createContainer(ctx context.Context, index int, podConfig } resp, err := d.client.ContainerCreate(ctx, cliContainerConfig, cliHostConfig, nil, "") - return &resp, err + return &resp, errors.WithStack(err) } func (d *DockerDriver) ExecutorGroup(ctx context.Context) (string, error) { @@ -361,12 +361,12 @@ func (d *DockerDriver) GetPods(ctx context.Context, all bool) ([]Pod, error) { All: all, }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } volumes, err := d.client.VolumeList(ctx, args) if err != nil { - return nil, err + return nil, errors.WithStack(err) } podsMap := map[string]*DockerPod{} @@ -549,11 +549,12 @@ type Stdin struct { } func (s *Stdin) Write(p []byte) (int, error) { - return s.hresp.Conn.Write(p) + n, err := s.hresp.Conn.Write(p) + return n, errors.WithStack(err) } func (s *Stdin) Close() error { - return s.hresp.CloseWrite() + return errors.WithStack(s.hresp.CloseWrite()) } func (dp *DockerPod) Exec(ctx context.Context, execConfig *ExecConfig) (ContainerExec, error) { @@ -564,7 +565,7 @@ func (dp *DockerPod) Exec(ctx context.Context, execConfig *ExecConfig) (Containe // Use a toolbox command that will set them up and then exec the real command. envj, err := json.Marshal(execConfig.Env) if err != nil { - return nil, err + return nil, errors.WithStack(err) } cmd := []string{filepath.Join(dp.initVolumeDir, "agola-toolbox"), "exec", "-e", string(envj), "-w", execConfig.WorkingDir, "--"} @@ -581,7 +582,7 @@ func (dp *DockerPod) Exec(ctx context.Context, execConfig *ExecConfig) (Containe response, err := dp.client.ContainerExecCreate(ctx, dp.containers[0].ID, dockerExecConfig) if err != nil { - return nil, err + return nil, errors.WithStack(err) } execStartCheck := dockertypes.ExecStartCheck{ Detach: dockerExecConfig.Detach, @@ -589,7 +590,7 @@ func (dp *DockerPod) Exec(ctx context.Context, execConfig *ExecConfig) (Containe } hresp, err := dp.client.ContainerExecAttach(ctx, response.ID, execStartCheck) if err != nil { - return nil, err + return nil, errors.WithStack(err) } stdout := execConfig.Stdout @@ -629,7 +630,7 @@ func (e *DockerContainerExec) Wait(ctx context.Context) (int, error) { // ignore error, we'll use the exit code of the exec select { case <-ctx.Done(): - return 0, ctx.Err() + return 0, errors.WithStack(ctx.Err()) case <-e.endCh: } @@ -637,7 +638,7 @@ func (e *DockerContainerExec) Wait(ctx context.Context) (int, error) { for { resp, err := e.client.ContainerExecInspect(ctx, e.execID) if err != nil { - return -1, err + return -1, errors.WithStack(err) } if !resp.Running { exitCode = resp.ExitCode diff --git a/internal/services/executor/driver/driver.go b/internal/services/executor/driver/driver.go index 918da6f..40b1817 100644 --- a/internal/services/executor/driver/driver.go +++ b/internal/services/executor/driver/driver.go @@ -21,6 +21,7 @@ import ( "os" "path/filepath" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/executor/registry" "agola.io/agola/services/types" ) @@ -121,7 +122,7 @@ func toolboxExecPath(toolboxDir string, arch types.Arch) (string, error) { toolboxPath := filepath.Join(toolboxDir, fmt.Sprintf("%s-linux-%s", toolboxPrefix, arch)) _, err := os.Stat(toolboxPath) if err != nil { - return "", err + return "", errors.WithStack(err) } return toolboxPath, nil } diff --git a/internal/services/executor/driver/k8s.go b/internal/services/executor/driver/k8s.go index b0b1edb..e80e5bb 100644 --- a/internal/services/executor/driver/k8s.go +++ b/internal/services/executor/driver/k8s.go @@ -26,6 +26,7 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/executor/registry" "agola.io/agola/internal/util" "agola.io/agola/services/types" @@ -33,7 +34,6 @@ import ( "github.com/docker/docker/pkg/archive" "github.com/gofrs/uuid" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" @@ -102,16 +102,16 @@ func NewK8sDriver(log zerolog.Logger, executorID, toolboxPath, initImage string, kubeClientConfig := NewKubeClientConfig("", "", "") kubecfg, err := kubeClientConfig.ClientConfig() if err != nil { - return nil, err + return nil, errors.WithStack(err) } kubecli, err := kubernetes.NewForConfig(kubecfg) if err != nil { - return nil, fmt.Errorf("cannot create kubernetes client: %w", err) + return nil, errors.Wrapf(err, "cannot create kubernetes client") } namespace, _, err := kubeClientConfig.Namespace() if err != nil { - return nil, err + return nil, errors.WithStack(err) } d := &K8sDriver{ @@ -128,7 +128,7 @@ func NewK8sDriver(log zerolog.Logger, executorID, toolboxPath, initImage string, serverVersion, err := d.client.Discovery().ServerVersion() if err != nil { - return nil, err + return nil, errors.WithStack(err) } sv, err := parseGitVersion(serverVersion.GitVersion) // if server version parsing fails just warn but ignore it @@ -144,7 +144,7 @@ func NewK8sDriver(log zerolog.Logger, executorID, toolboxPath, initImage string, lists, err := d.client.Discovery().ServerPreferredResources() if err != nil { - return nil, err + return nil, errors.WithStack(err) } hasLeaseAPI := false @@ -165,7 +165,7 @@ func NewK8sDriver(log zerolog.Logger, executorID, toolboxPath, initImage string, executorsGroupID, err := d.getOrCreateExecutorsGroupID(context.TODO()) if err != nil { - return nil, err + return nil, errors.WithStack(err) } d.executorsGroupID = executorsGroupID @@ -258,7 +258,7 @@ func (d *K8sDriver) Archs(ctx context.Context) ([]types.Arch, error) { // TODO(sgotti) use go client listers instead of querying every time nodes, err := d.nodeLister.List(apilabels.SelectorFromSet(nil)) if err != nil { - return nil, err + return nil, errors.WithStack(err) } archsMap := map[types.Arch]struct{}{} archs := []types.Arch{} @@ -291,7 +291,7 @@ func (d *K8sDriver) getOrCreateExecutorsGroupID(ctx context.Context) (string, er cm, err := cmClient.Get(configMapName, metav1.GetOptions{}) if err != nil { if !apierrors.IsNotFound(err) { - return "", err + return "", errors.WithStack(err) } } else { return cm.Data[executorsGroupIDConfigMapKey], nil @@ -306,7 +306,7 @@ func (d *K8sDriver) getOrCreateExecutorsGroupID(ctx context.Context) (string, er Data: map[string]string{executorsGroupIDConfigMapKey: executorsGroupID}, } if _, err = cmClient.Create(cm); err != nil { - return "", err + return "", errors.WithStack(err) } return executorsGroupID, nil @@ -332,12 +332,12 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri dockerconfigj, err := json.Marshal(podConfig.DockerConfig) if err != nil { - return nil, err + return nil, errors.WithStack(err) } initDockerconfigj, err := json.Marshal(d.initDockerConfig) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // secret that hold the docker registry auth @@ -354,7 +354,7 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri _, err = secretClient.Create(secret) if err != nil { - return nil, err + return nil, errors.WithStack(err) } pod := &corev1.Pod{ @@ -469,14 +469,14 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri pod, err = podClient.Create(pod) if err != nil { - return nil, err + return nil, errors.WithStack(err) } watcher, err := podClient.Watch( metav1.SingleObject(pod.ObjectMeta), ) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // wait for init container to be ready @@ -499,7 +499,7 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri // Remove init container docker auth so it won't be used by user defined containers dur := int64(0) if err := secretClient.Delete(name, &metav1.DeleteOptions{GracePeriodSeconds: &dur}); err != nil { - return nil, err + return nil, errors.WithStack(err) } secret = &corev1.Secret{ @@ -515,12 +515,12 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri _, err = secretClient.Create(secret) if err != nil { - return nil, err + return nil, errors.WithStack(err) } coreclient, err := corev1client.NewForConfig(d.restconfig) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // get the pod arch @@ -540,7 +540,7 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri exec, err := remotecommand.NewSPDYExecutor(d.restconfig, "POST", req.URL()) if err != nil { - return nil, errors.Errorf("failed to generate k8s client spdy executor for url %q, method: POST: %w", req.URL(), err) + return nil, errors.Wrapf(err, "failed to generate k8s client spdy executor for url %q, method: POST", req.URL()) } stdout := bytes.Buffer{} @@ -549,7 +549,7 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri Stderr: out, }) if err != nil { - return nil, errors.Errorf("failed to execute command on initcontainer: %w", err) + return nil, errors.Wrapf(err, "failed to execute command on initcontainer") } osArch := strings.TrimSpace(stdout.String()) @@ -566,17 +566,17 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri // copy the toolbox for the pod arch toolboxExecPath, err := toolboxExecPath(d.toolboxPath, arch) if err != nil { - return nil, errors.Errorf("failed to get toolbox path for arch %q: %w", arch, err) + return nil, errors.Wrapf(err, "failed to get toolbox path for arch %q", arch) } srcInfo, err := archive.CopyInfoSourcePath(toolboxExecPath, false) if err != nil { - return nil, err + return nil, errors.WithStack(err) } srcInfo.RebaseName = "agola-toolbox" srcArchive, err := archive.TarResource(srcInfo) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer srcArchive.Close() @@ -597,7 +597,7 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri exec, err = remotecommand.NewSPDYExecutor(d.restconfig, "POST", req.URL()) if err != nil { - return nil, errors.Errorf("failed to generate k8s client spdy executor for url %q, method: POST: %w", req.URL(), err) + return nil, errors.Wrapf(err, "failed to generate k8s client spdy executor for url %q, method: POST", req.URL()) } fmt.Fprintf(out, "extracting toolbox\n") @@ -607,7 +607,7 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri Stderr: out, }) if err != nil { - return nil, errors.Errorf("failed to execute command on initcontainer: %w", err) + return nil, errors.Wrapf(err, "failed to execute command on initcontainer") } fmt.Fprintf(out, "extracting toolbox done\n") @@ -627,7 +627,7 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri exec, err = remotecommand.NewSPDYExecutor(d.restconfig, "POST", req.URL()) if err != nil { - return nil, errors.Errorf("failed to generate k8s client spdy executor for url %q, method: POST: %w", req.URL(), err) + return nil, errors.Wrapf(err, "failed to generate k8s client spdy executor for url %q, method: POST", req.URL()) } err = exec.Stream(remotecommand.StreamOptions{ @@ -635,14 +635,14 @@ func (d *K8sDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.Wri Stderr: out, }) if err != nil { - return nil, errors.Errorf("failed to execute command on initcontainer: %w", err) + return nil, errors.Wrapf(err, "failed to execute command on initcontainer") } watcher, err = podClient.Watch( metav1.SingleObject(pod.ObjectMeta), ) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // wait for pod to be initialized @@ -676,7 +676,7 @@ func (d *K8sDriver) GetPods(ctx context.Context, all bool) ([]Pod, error) { k8sPods, err := d.podLister.List(apilabels.SelectorFromSet(labels)) if err != nil { - return nil, err + return nil, errors.WithStack(err) } pods := make([]Pod, len(k8sPods)) @@ -716,11 +716,11 @@ func (p *K8sPod) Stop(ctx context.Context) error { d := int64(0) secretClient := p.client.CoreV1().Secrets(p.namespace) if err := secretClient.Delete(p.id, &metav1.DeleteOptions{GracePeriodSeconds: &d}); err != nil { - return err + return errors.WithStack(err) } podClient := p.client.CoreV1().Pods(p.namespace) if err := podClient.Delete(p.id, &metav1.DeleteOptions{GracePeriodSeconds: &d}); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -740,14 +740,14 @@ func (p *K8sPod) Exec(ctx context.Context, execConfig *ExecConfig) (ContainerExe coreclient, err := corev1client.NewForConfig(p.restconfig) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // k8s pod exec api doesn't let us define the workingdir and the environment. // Use a toolbox command that will set them up and then exec the real command. envj, err := json.Marshal(execConfig.Env) if err != nil { - return nil, err + return nil, errors.WithStack(err) } cmd := []string{filepath.Join(p.initVolumeDir, "agola-toolbox"), "exec", "-e", string(envj), "-w", execConfig.WorkingDir, "--"} cmd = append(cmd, execConfig.Cmd...) @@ -769,7 +769,7 @@ func (p *K8sPod) Exec(ctx context.Context, execConfig *ExecConfig) (ContainerExe exec, err := remotecommand.NewSPDYExecutor(p.restconfig, "POST", req.URL()) if err != nil { - return nil, err + return nil, errors.WithStack(err) } reader, writer := io.Pipe() @@ -804,7 +804,7 @@ func (e *K8sContainerExec) Wait(ctx context.Context) (int, error) { if errors.As(err, &verr) { exitCode = verr.ExitStatus() } else { - return -1, err + return -1, errors.WithStack(err) } } @@ -834,17 +834,17 @@ var gitVersionRegex = regexp.MustCompile("v([0-9]+).([0-9]+).[0-9]+.*") func parseGitVersion(gitVersion string) (*serverVersion, error) { parsedVersion := gitVersionRegex.FindStringSubmatch(gitVersion) if len(parsedVersion) != 3 { - return nil, fmt.Errorf("cannot parse git version %s", gitVersion) + return nil, errors.Errorf("cannot parse git version %s", gitVersion) } sv := &serverVersion{} var err error sv.Major, err = strconv.Atoi(parsedVersion[1]) if err != nil { - return nil, err + return nil, errors.WithStack(err) } sv.Minor, err = strconv.Atoi(parsedVersion[2]) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return sv, nil } diff --git a/internal/services/executor/driver/k8slease.go b/internal/services/executor/driver/k8slease.go index 3fb900f..c69ecff 100644 --- a/internal/services/executor/driver/k8slease.go +++ b/internal/services/executor/driver/k8slease.go @@ -19,7 +19,7 @@ import ( "encoding/json" "time" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/errors" coordinationv1 "k8s.io/api/coordination/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -52,7 +52,7 @@ func (d *K8sDriver) updateLease(ctx context.Context) error { lease, err := leaseClient.Get(name, metav1.GetOptions{}) if err != nil { if !apierrors.IsNotFound(err) { - return err + return errors.WithStack(err) } } else { found = true @@ -61,7 +61,7 @@ func (d *K8sDriver) updateLease(ctx context.Context) error { if found { lease.Spec.RenewTime = &now _, err := leaseClient.Update(lease) - return err + return errors.WithStack(err) } lease = &coordinationv1.Lease{ @@ -77,14 +77,14 @@ func (d *K8sDriver) updateLease(ctx context.Context) error { }, } _, err = leaseClient.Create(lease) - return err + return errors.WithStack(err) } else { cmClient := d.client.CoreV1().ConfigMaps(d.namespace) found := false cm, err := cmClient.Get(name, metav1.GetOptions{}) if err != nil { if !apierrors.IsNotFound(err) { - return err + return errors.WithStack(err) } } else { found = true @@ -103,22 +103,22 @@ func (d *K8sDriver) updateLease(ctx context.Context) error { } if recordBytes, found := cm.Annotations[cmLeaseKey]; found { if err := json.Unmarshal([]byte(recordBytes), &ld); err != nil { - return err + return errors.WithStack(err) } } ld.RenewTime = now ldj, err := json.Marshal(ld) if err != nil { - return err + return errors.WithStack(err) } cm.Annotations[cmLeaseKey] = string(ldj) _, err = cmClient.Update(cm) - return err + return errors.WithStack(err) } ldj, err := json.Marshal(ld) if err != nil { - return err + return errors.WithStack(err) } cm = &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -129,7 +129,7 @@ func (d *K8sDriver) updateLease(ctx context.Context) error { } cm.Annotations[cmLeaseKey] = string(ldj) _, err = cmClient.Create(cm) - return err + return errors.WithStack(err) } } @@ -144,7 +144,7 @@ func (d *K8sDriver) getLeases(ctx context.Context) ([]string, error) { leases, err := leaseClient.List(metav1.ListOptions{LabelSelector: apilabels.SelectorFromSet(labels).String()}) if err != nil { - return nil, err + return nil, errors.WithStack(err) } for _, lease := range leases.Items { if v, ok := lease.Labels[executorIDKey]; ok { @@ -156,7 +156,7 @@ func (d *K8sDriver) getLeases(ctx context.Context) ([]string, error) { cms, err := cmClient.List(metav1.ListOptions{LabelSelector: apilabels.SelectorFromSet(labels).String()}) if err != nil { - return nil, err + return nil, errors.WithStack(err) } for _, cm := range cms.Items { if v, ok := cm.Labels[executorIDKey]; ok { @@ -177,7 +177,7 @@ func (d *K8sDriver) cleanStaleExecutorsLease(ctx context.Context) error { leases, err := d.leaseLister.List(apilabels.SelectorFromSet(labels)) if err != nil { - return err + return errors.WithStack(err) } for _, lease := range leases { if lease.Spec.HolderIdentity == nil { @@ -204,7 +204,7 @@ func (d *K8sDriver) cleanStaleExecutorsLease(ctx context.Context) error { cms, err := d.cmLister.List(apilabels.SelectorFromSet(labels)) if err != nil { - return err + return errors.WithStack(err) } for _, cm := range cms { var ld *LeaseData @@ -215,7 +215,7 @@ func (d *K8sDriver) cleanStaleExecutorsLease(ctx context.Context) error { } if recordBytes, found := cm.Annotations[cmLeaseKey]; found { if err := json.Unmarshal([]byte(recordBytes), &ld); err != nil { - return err + return errors.WithStack(err) } } // skip our lease diff --git a/internal/services/executor/executor.go b/internal/services/executor/executor.go index 755d963..6334afe 100644 --- a/internal/services/executor/executor.go +++ b/internal/services/executor/executor.go @@ -31,6 +31,8 @@ import ( "time" "agola.io/agola/internal/common" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/services/config" "agola.io/agola/internal/services/executor/driver" "agola.io/agola/internal/services/executor/registry" @@ -43,7 +45,6 @@ import ( sockaddr "github.com/hashicorp/go-sockaddr" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - errors "golang.org/x/xerrors" ) const ( @@ -57,7 +58,8 @@ var ( ) func (e *Executor) getAllPods(ctx context.Context, all bool) ([]driver.Pod, error) { - return e.driver.GetPods(ctx, all) + pods, err := e.driver.GetPods(ctx, all) + return pods, errors.WithStack(err) } func stepUser(t *types.ExecutorTask) string { @@ -84,7 +86,7 @@ func (e *Executor) createFile(ctx context.Context, pod driver.Pod, command, user ce, err := pod.Exec(ctx, execConfig) if err != nil { - return "", err + return "", errors.WithStack(err) } stdin := ce.Stdin() @@ -95,7 +97,7 @@ func (e *Executor) createFile(ctx context.Context, pod driver.Pod, command, user exitCode, err := ce.Wait(ctx) if err != nil { - return "", err + return "", errors.WithStack(err) } if exitCode != 0 { return "", errors.Errorf("toolbox exited with code: %d", exitCode) @@ -106,11 +108,11 @@ func (e *Executor) createFile(ctx context.Context, pod driver.Pod, command, user func (e *Executor) doRunStep(ctx context.Context, s *types.RunStep, t *types.ExecutorTask, pod driver.Pod, logPath string) (int, error) { if err := os.MkdirAll(filepath.Dir(logPath), 0770); err != nil { - return -1, err + return -1, errors.WithStack(err) } outf, err := os.Create(logPath) if err != nil { - return -1, err + return -1, errors.WithStack(err) } defer outf.Close() @@ -155,7 +157,7 @@ func (e *Executor) doRunStep(ctx context.Context, s *types.RunStep, t *types.Exe workingDir, err = e.expandDir(ctx, t, pod, outf, workingDir) if err != nil { _, _ = outf.WriteString(fmt.Sprintf("failed to expand working dir %q. Error: %s\n", workingDir, err)) - return -1, err + return -1, errors.WithStack(err) } execConfig := &driver.ExecConfig{ @@ -171,12 +173,12 @@ func (e *Executor) doRunStep(ctx context.Context, s *types.RunStep, t *types.Exe ce, err := pod.Exec(ctx, execConfig) if err != nil { - return -1, err + return -1, errors.WithStack(err) } exitCode, err := ce.Wait(ctx) if err != nil { - return -1, err + return -1, errors.WithStack(err) } return exitCode, nil @@ -186,27 +188,27 @@ func (e *Executor) doSaveToWorkspaceStep(ctx context.Context, s *types.SaveToWor cmd := []string{toolboxContainerPath, "archive"} if err := os.MkdirAll(filepath.Dir(logPath), 0770); err != nil { - return -1, err + return -1, errors.WithStack(err) } logf, err := os.Create(logPath) if err != nil { - return -1, err + return -1, errors.WithStack(err) } defer logf.Close() if err := os.MkdirAll(filepath.Dir(archivePath), 0770); err != nil { - return -1, err + return -1, errors.WithStack(err) } archivef, err := os.Create(archivePath) if err != nil { - return -1, err + return -1, errors.WithStack(err) } defer archivef.Close() workingDir, err := e.expandDir(ctx, t, pod, logf, t.Spec.WorkingDir) if err != nil { _, _ = logf.WriteString(fmt.Sprintf("failed to expand working dir %q. Error: %s\n", t.Spec.WorkingDir, err)) - return -1, err + return -1, errors.WithStack(err) } execConfig := &driver.ExecConfig{ @@ -221,7 +223,7 @@ func (e *Executor) doSaveToWorkspaceStep(ctx context.Context, s *types.SaveToWor ce, err := pod.Exec(ctx, execConfig) if err != nil { - return -1, err + return -1, errors.WithStack(err) } type ArchiveInfo struct { @@ -258,7 +260,7 @@ func (e *Executor) doSaveToWorkspaceStep(ctx context.Context, s *types.SaveToWor exitCode, err := ce.Wait(ctx) if err != nil { - return -1, err + return -1, errors.WithStack(err) } return exitCode, nil @@ -282,12 +284,12 @@ func (e *Executor) expandDir(ctx context.Context, t *types.ExecutorTask, pod dri ce, err := pod.Exec(ctx, execConfig) if err != nil { - return "", err + return "", errors.WithStack(err) } exitCode, err := ce.Wait(ctx) if err != nil { - return "", err + return "", errors.WithStack(err) } if exitCode != 0 { return "", errors.Errorf("expanddir ended with exit code %d", exitCode) @@ -311,12 +313,12 @@ func (e *Executor) mkdir(ctx context.Context, t *types.ExecutorTask, pod driver. ce, err := pod.Exec(ctx, execConfig) if err != nil { - return err + return errors.WithStack(err) } exitCode, err := ce.Wait(ctx) if err != nil { - return err + return errors.WithStack(err) } if exitCode != 0 { return errors.Errorf("mkdir ended with exit code %d", exitCode) @@ -334,7 +336,7 @@ func (e *Executor) template(ctx context.Context, t *types.ExecutorTask, pod driv workingDir, err := e.expandDir(ctx, t, pod, logf, t.Spec.WorkingDir) if err != nil { _, _ = io.WriteString(logf, fmt.Sprintf("failed to expand working dir %q. Error: %s\n", t.Spec.WorkingDir, err)) - return "", err + return "", errors.WithStack(err) } execConfig := &driver.ExecConfig{ @@ -349,7 +351,7 @@ func (e *Executor) template(ctx context.Context, t *types.ExecutorTask, pod driv ce, err := pod.Exec(ctx, execConfig) if err != nil { - return "", err + return "", errors.WithStack(err) } stdin := ce.Stdin() @@ -360,7 +362,7 @@ func (e *Executor) template(ctx context.Context, t *types.ExecutorTask, pod driv exitCode, err := ce.Wait(ctx) if err != nil { - return "", err + return "", errors.WithStack(err) } if exitCode != 0 { return "", errors.Errorf("template ended with exit code %d", exitCode) @@ -382,7 +384,7 @@ func (e *Executor) unarchive(ctx context.Context, t *types.ExecutorTask, source workingDir, err := e.expandDir(ctx, t, pod, logf, t.Spec.WorkingDir) if err != nil { _, _ = io.WriteString(logf, fmt.Sprintf("failed to expand working dir %q. Error: %s\n", t.Spec.WorkingDir, err)) - return err + return errors.WithStack(err) } execConfig := &driver.ExecConfig{ @@ -397,7 +399,7 @@ func (e *Executor) unarchive(ctx context.Context, t *types.ExecutorTask, source ce, err := pod.Exec(ctx, execConfig) if err != nil { - return err + return errors.WithStack(err) } stdin := ce.Stdin() @@ -408,7 +410,7 @@ func (e *Executor) unarchive(ctx context.Context, t *types.ExecutorTask, source exitCode, err := ce.Wait(ctx) if err != nil { - return err + return errors.WithStack(err) } if exitCode != 0 { return errors.Errorf("unarchive ended with exit code %d", exitCode) @@ -419,11 +421,11 @@ func (e *Executor) unarchive(ctx context.Context, t *types.ExecutorTask, source func (e *Executor) doRestoreWorkspaceStep(ctx context.Context, s *types.RestoreWorkspaceStep, t *types.ExecutorTask, pod driver.Pod, logPath string) (int, error) { if err := os.MkdirAll(filepath.Dir(logPath), 0770); err != nil { - return -1, err + return -1, errors.WithStack(err) } logf, err := os.Create(logPath) if err != nil { - return -1, err + return -1, errors.WithStack(err) } defer logf.Close() @@ -433,12 +435,12 @@ func (e *Executor) doRestoreWorkspaceStep(ctx context.Context, s *types.RestoreW if err != nil { // TODO(sgotti) retry before giving up fmt.Fprintf(logf, "error reading workspace archive: %v\n", err) - return -1, err + return -1, errors.WithStack(err) } archivef := resp.Body if err := e.unarchive(ctx, t, archivef, pod, logf, s.DestDir, false, false); err != nil { archivef.Close() - return -1, err + return -1, errors.WithStack(err) } archivef.Close() } @@ -450,11 +452,11 @@ func (e *Executor) doSaveCacheStep(ctx context.Context, s *types.SaveCacheStep, cmd := []string{toolboxContainerPath, "archive"} if err := os.MkdirAll(filepath.Dir(logPath), 0770); err != nil { - return -1, err + return -1, errors.WithStack(err) } logf, err := os.Create(logPath) if err != nil { - return -1, err + return -1, errors.WithStack(err) } defer logf.Close() @@ -463,7 +465,7 @@ func (e *Executor) doSaveCacheStep(ctx context.Context, s *types.SaveCacheStep, // calculate key from template userKey, err := e.template(ctx, t, pod, logf, s.Key) if err != nil { - return -1, err + return -1, errors.WithStack(err) } fmt.Fprintf(logf, "cache key %q\n", userKey) @@ -480,7 +482,7 @@ func (e *Executor) doSaveCacheStep(ctx context.Context, s *types.SaveCacheStep, } else { // TODO(sgotti) retry before giving up fmt.Fprintf(logf, "error checking for cache key %q: %v\n", userKey, err) - return -1, err + return -1, errors.WithStack(err) } } if !save { @@ -490,18 +492,18 @@ func (e *Executor) doSaveCacheStep(ctx context.Context, s *types.SaveCacheStep, fmt.Fprintf(logf, "archiving cache with key %q\n", userKey) if err := os.MkdirAll(filepath.Dir(archivePath), 0770); err != nil { - return -1, err + return -1, errors.WithStack(err) } archivef, err := os.Create(archivePath) if err != nil { - return -1, err + return -1, errors.WithStack(err) } defer archivef.Close() workingDir, err := e.expandDir(ctx, t, pod, logf, t.Spec.WorkingDir) if err != nil { _, _ = io.WriteString(logf, fmt.Sprintf("failed to expand working dir %q. Error: %s\n", t.Spec.WorkingDir, err)) - return -1, err + return -1, errors.WithStack(err) } execConfig := &driver.ExecConfig{ @@ -516,7 +518,7 @@ func (e *Executor) doSaveCacheStep(ctx context.Context, s *types.SaveCacheStep, ce, err := pod.Exec(ctx, execConfig) if err != nil { - return -1, err + return -1, errors.WithStack(err) } type ArchiveInfo struct { @@ -553,7 +555,7 @@ func (e *Executor) doSaveCacheStep(ctx context.Context, s *types.SaveCacheStep, exitCode, err := ce.Wait(ctx) if err != nil { - return -1, err + return -1, errors.WithStack(err) } if exitCode != 0 { @@ -562,11 +564,11 @@ func (e *Executor) doSaveCacheStep(ctx context.Context, s *types.SaveCacheStep, f, err := os.Open(archivePath) if err != nil { - return -1, err + return -1, errors.WithStack(err) } fi, err := f.Stat() if err != nil { - return -1, err + return -1, errors.WithStack(err) } // send cache archive to scheduler @@ -574,7 +576,7 @@ func (e *Executor) doSaveCacheStep(ctx context.Context, s *types.SaveCacheStep, if resp != nil && resp.StatusCode == http.StatusNotModified { return exitCode, nil } - return -1, err + return -1, errors.WithStack(err) } return exitCode, nil @@ -582,11 +584,11 @@ func (e *Executor) doSaveCacheStep(ctx context.Context, s *types.SaveCacheStep, func (e *Executor) doRestoreCacheStep(ctx context.Context, s *types.RestoreCacheStep, t *types.ExecutorTask, pod driver.Pod, logPath string) (int, error) { if err := os.MkdirAll(filepath.Dir(logPath), 0770); err != nil { - return -1, err + return -1, errors.WithStack(err) } logf, err := os.Create(logPath) if err != nil { - return -1, err + return -1, errors.WithStack(err) } defer logf.Close() @@ -595,7 +597,7 @@ func (e *Executor) doRestoreCacheStep(ctx context.Context, s *types.RestoreCache // calculate key from template userKey, err := e.template(ctx, t, pod, logf, key) if err != nil { - return -1, err + return -1, errors.WithStack(err) } fmt.Fprintf(logf, "cache key %q\n", userKey) @@ -611,13 +613,13 @@ func (e *Executor) doRestoreCacheStep(ctx context.Context, s *types.RestoreCache } // TODO(sgotti) retry before giving up fmt.Fprintf(logf, "error reading cache: %v\n", err) - return -1, err + return -1, errors.WithStack(err) } fmt.Fprintf(logf, "restoring cache with key %q\n", userKey) cachef := resp.Body if err := e.unarchive(ctx, t, cachef, pod, logf, s.DestDir, false, false); err != nil { cachef.Close() - return -1, err + return -1, errors.WithStack(err) } cachef.Close() @@ -666,21 +668,21 @@ func (e *Executor) sendExecutorStatus(ctx context.Context) error { archs, err := e.driver.Archs(ctx) if err != nil { - return err + return errors.WithStack(err) } executorGroup, err := e.driver.ExecutorGroup(ctx) if err != nil { - return err + return errors.WithStack(err) } // report all the executors that are active OR that have some owned pods not yet removed activeExecutors, err := e.driver.GetExecutors(ctx) if err != nil { - return err + return errors.WithStack(err) } pods, err := e.driver.GetPods(ctx, true) if err != nil { - return err + return errors.WithStack(err) } executorsMap := map[string]struct{}{} @@ -710,13 +712,13 @@ func (e *Executor) sendExecutorStatus(ctx context.Context) error { e.log.Debug().Msgf("send executor status: %s", util.Dump(executor)) _, err = e.runserviceClient.SendExecutorStatus(ctx, executor) - return err + return errors.WithStack(err) } func (e *Executor) sendExecutorTaskStatus(ctx context.Context, et *types.ExecutorTask) error { e.log.Debug().Msgf("send executor task: %s. status: %s", et.ID, et.Status.Phase) _, err := e.runserviceClient.SendExecutorTaskStatus(ctx, e.id, et) - return err + return errors.WithStack(err) } func (e *Executor) executeTask(rt *runningTask) { @@ -802,19 +804,19 @@ func (e *Executor) executeTask(rt *runningTask) { func (e *Executor) setupTask(ctx context.Context, rt *runningTask) error { et := rt.et if err := os.RemoveAll(e.taskPath(et.ID)); err != nil { - return err + return errors.WithStack(err) } if err := os.MkdirAll(e.taskPath(et.ID), 0770); err != nil { - return err + return errors.WithStack(err) } setupLogPath := e.setupLogPath(et.ID) if err := os.MkdirAll(filepath.Dir(setupLogPath), 0770); err != nil { - return err + return errors.WithStack(err) } outf, err := os.Create(setupLogPath) if err != nil { - return err + return errors.WithStack(err) } defer outf.Close() @@ -835,7 +837,7 @@ func (e *Executor) setupTask(ctx context.Context, rt *runningTask) error { dockerConfig, err := registry.GenDockerConfig(et.Spec.DockerRegistriesAuth, []string{et.Spec.Containers[0].Image}) if err != nil { - return err + return errors.WithStack(err) } podConfig := &driver.PodConfig{ @@ -884,7 +886,7 @@ func (e *Executor) setupTask(ctx context.Context, rt *runningTask) error { pod, err := e.driver.NewPod(ctx, podConfig, outf) if err != nil { _, _ = outf.WriteString(fmt.Sprintf("Pod failed to start. Error: %s\n", err)) - return err + return errors.WithStack(err) } _, _ = outf.WriteString("Pod started.\n") @@ -892,7 +894,7 @@ func (e *Executor) setupTask(ctx context.Context, rt *runningTask) error { _, _ = outf.WriteString(fmt.Sprintf("Creating working dir %q.\n", et.Spec.WorkingDir)) if err := e.mkdir(ctx, et, pod, outf, et.Spec.WorkingDir); err != nil { _, _ = outf.WriteString(fmt.Sprintf("Failed to create working dir %q. Error: %s\n", et.Spec.WorkingDir, err)) - return err + return errors.WithStack(err) } } @@ -959,7 +961,7 @@ func (e *Executor) executeTaskSteps(ctx context.Context, rt *runningTask, pod dr } else { rt.et.Status.Steps[i].Phase = types.ExecutorTaskPhaseFailed } - serr = errors.Errorf("failed to execute step %s: %w", util.Dump(step), err) + serr = errors.Wrapf(err, "failed to execute step %s", util.Dump(step)) } else if exitCode != 0 { if rt.et.Spec.Stop { rt.et.Status.Steps[i].Phase = types.ExecutorTaskPhaseStopped @@ -978,7 +980,7 @@ func (e *Executor) executeTaskSteps(ctx context.Context, rt *runningTask, pod dr rt.Unlock() if serr != nil { - return i, serr + return i, errors.WithStack(serr) } } @@ -1005,11 +1007,11 @@ func (e *Executor) podsCleanerLoop(ctx context.Context) { func (e *Executor) podsCleaner(ctx context.Context) error { pods, err := e.getAllPods(ctx, true) if err != nil { - return err + return errors.WithStack(err) } executors, err := e.driver.GetExecutors(ctx) if err != nil { - return err + return errors.WithStack(err) } // always add ourself to executors executors = append(executors, e.id) @@ -1118,7 +1120,7 @@ func (e *Executor) tasksUpdater(ctx context.Context) error { ets, _, err := e.runserviceClient.GetExecutorTasks(ctx, e.id) if err != nil { e.log.Warn().Err(err).Send() - return err + return errors.WithStack(err) } e.log.Debug().Msgf("ets: %v", util.Dump(ets)) for _, et := range ets { @@ -1239,7 +1241,7 @@ func (e *Executor) tasksDataCleanerLoop(ctx context.Context) { func (e *Executor) tasksDataCleaner(ctx context.Context) error { entries, err := ioutil.ReadDir(e.tasksDir()) if err != nil { - return err + return errors.WithStack(err) } for _, entry := range entries { @@ -1251,10 +1253,10 @@ func (e *Executor) tasksDataCleaner(ctx context.Context) error { _, resp, err := e.runserviceClient.GetExecutorTask(ctx, e.id, etID) if err != nil { if resp == nil { - return err + return errors.WithStack(err) } if resp.StatusCode != http.StatusNotFound { - return err + return errors.WithStack(err) } } if resp.StatusCode == http.StatusNotFound { @@ -1262,7 +1264,7 @@ func (e *Executor) tasksDataCleaner(ctx context.Context) error { e.log.Info().Msgf("removing task dir %q", taskDir) // remove task dir if err := os.RemoveAll(taskDir); err != nil { - return err + return errors.WithStack(err) } } } @@ -1333,14 +1335,14 @@ func (e *Executor) handleTasks(ctx context.Context, c <-chan *types.ExecutorTask func (e *Executor) getExecutorID() (string, error) { id, err := ioutil.ReadFile(e.executorIDPath()) if err != nil && !os.IsNotExist(err) { - return "", err + return "", errors.WithStack(err) } return string(id), nil } func (e *Executor) saveExecutorID(id string) error { if err := common.WriteFileAtomic(e.executorIDPath(), []byte(id), 0660); err != nil { - return errors.Errorf("failed to write executor id file: %w", err) + return errors.Wrapf(err, "failed to write executor id file") } return nil } @@ -1365,7 +1367,7 @@ func NewExecutor(ctx context.Context, log zerolog.Logger, c *config.Executor) (* var err error c.ToolboxPath, err = filepath.Abs(c.ToolboxPath) if err != nil { - return nil, errors.Errorf("cannot determine \"agola-toolbox\" absolute path: %w", err) + return nil, errors.Wrapf(err, "cannot determine \"agola-toolbox\" absolute path") } e := &Executor{ @@ -1378,17 +1380,17 @@ func NewExecutor(ctx context.Context, log zerolog.Logger, c *config.Executor) (* } if err := os.MkdirAll(e.tasksDir(), 0770); err != nil { - return nil, err + return nil, errors.WithStack(err) } id, err := e.getExecutorID() if err != nil { - return nil, err + return nil, errors.WithStack(err) } if id == "" { id = uuid.Must(uuid.NewV4()).String() if err := e.saveExecutorID(id); err != nil { - return nil, err + return nil, errors.WithStack(err) } } @@ -1398,7 +1400,7 @@ func NewExecutor(ctx context.Context, log zerolog.Logger, c *config.Executor) (* // improve this to let the user define the bind and the advertize address addr, err := sockaddr.GetPrivateIP() if err != nil { - return nil, errors.Errorf("cannot discover executor listen address: %w", err) + return nil, errors.Wrapf(err, "cannot discover executor listen address") } if addr == "" { return nil, errors.Errorf("cannot discover executor listen address") @@ -1409,7 +1411,7 @@ func NewExecutor(ctx context.Context, log zerolog.Logger, c *config.Executor) (* } _, port, err := net.SplitHostPort(c.Web.ListenAddress) if err != nil { - return nil, errors.Errorf("cannot get web listen port: %w", err) + return nil, errors.Wrapf(err, "cannot get web listen port") } u.Host = net.JoinHostPort(addr, port) e.listenURL = u.String() @@ -1421,7 +1423,7 @@ func NewExecutor(ctx context.Context, log zerolog.Logger, c *config.Executor) (* if e.c.InitImage.Auth != nil { regName, err := registry.GetRegistry(e.c.InitImage.Image) if err != nil { - return nil, err + return nil, errors.WithStack(err) } dockerAuthConfig := types.DockerRegistryAuth{ @@ -1432,7 +1434,7 @@ func NewExecutor(ctx context.Context, log zerolog.Logger, c *config.Executor) (* } initDockerConfig, err = registry.GenDockerConfig(map[string]types.DockerRegistryAuth{regName: dockerAuthConfig}, []string{e.c.InitImage.Image}) if err != nil { - return nil, err + return nil, errors.WithStack(err) } } @@ -1441,12 +1443,12 @@ func NewExecutor(ctx context.Context, log zerolog.Logger, c *config.Executor) (* case config.DriverTypeDocker: d, err = driver.NewDockerDriver(log, e.id, e.c.ToolboxPath, e.c.InitImage.Image, initDockerConfig) if err != nil { - return nil, errors.Errorf("failed to create docker driver: %w", err) + return nil, errors.Wrapf(err, "failed to create docker driver") } case config.DriverTypeK8s: d, err = driver.NewK8sDriver(log, e.id, c.ToolboxPath, e.c.InitImage.Image, initDockerConfig) if err != nil { - return nil, errors.Errorf("failed to create kubernetes driver: %w", err) + return nil, errors.Wrapf(err, "failed to create kubernetes driver") } e.dynamic = true default: @@ -1459,7 +1461,7 @@ func NewExecutor(ctx context.Context, log zerolog.Logger, c *config.Executor) (* func (e *Executor) Run(ctx context.Context) error { if err := e.driver.Setup(ctx); err != nil { - return err + return errors.WithStack(err) } ch := make(chan *types.ExecutorTask) @@ -1502,7 +1504,7 @@ func (e *Executor) Run(ctx context.Context) error { case err := <-lerrCh: if err != nil { log.Err(err).Msgf("http server listen error") - return err + return errors.WithStack(err) } } diff --git a/internal/services/executor/registry/registry.go b/internal/services/executor/registry/registry.go index a69e458..5f31864 100644 --- a/internal/services/executor/registry/registry.go +++ b/internal/services/executor/registry/registry.go @@ -19,8 +19,8 @@ import ( "fmt" "strings" + "agola.io/agola/internal/errors" "agola.io/agola/services/runservice/types" - errors "golang.org/x/xerrors" "github.com/google/go-containerregistry/pkg/name" ) @@ -79,7 +79,7 @@ var ( func GetImageTagOrDigest(image string) (string, error) { ref, err := name.ParseReference(image, name.WeakValidation) if err != nil { - return "", err + return "", errors.WithStack(err) } return ref.Identifier(), nil } @@ -87,7 +87,7 @@ func GetImageTagOrDigest(image string) (string, error) { func GetRegistry(image string) (string, error) { ref, err := name.ParseReference(image, name.WeakValidation) if err != nil { - return "", err + return "", errors.WithStack(err) } regName := ref.Context().RegistryStr() return regName, nil @@ -102,17 +102,17 @@ func ResolveAuth(auths map[string]types.DockerRegistryAuth, regname string) (str case types.DockerRegistryAuthTypeEncodedAuth: decoded, err := base64.StdEncoding.DecodeString(auth.Auth) if err != nil { - return "", "", errors.Errorf("failed to decode docker auth: %w", err) + return "", "", errors.Wrapf(err, "failed to decode docker auth") } parts := strings.Split(string(decoded), ":") if len(parts) != 2 { - return "", "", errors.Errorf("wrong docker auth: %w", err) + return "", "", errors.Wrapf(err, "wrong docker auth") } return parts[0], parts[1], nil case types.DockerRegistryAuthTypeBasic: return auth.Username, auth.Password, nil default: - return "", "", fmt.Errorf("unsupported auth type %q", auth.Type) + return "", "", errors.Errorf("unsupported auth type %q", auth.Type) } } } @@ -126,7 +126,7 @@ func GenDockerConfig(auths map[string]types.DockerRegistryAuth, images []string) for _, image := range images { ref, err := name.ParseReference(image, name.WeakValidation) if err != nil { - return nil, err + return nil, errors.WithStack(err) } regName := ref.Context().RegistryStr() @@ -136,7 +136,7 @@ func GenDockerConfig(auths map[string]types.DockerRegistryAuth, images []string) username, password, err := ResolveAuth(auths, regName) if err != nil { - return nil, errors.Errorf("failed to resolve auth: %w", err) + return nil, errors.Wrapf(err, "failed to resolve auth") } delimited := fmt.Sprintf("%s:%s", username, password) auth := base64.StdEncoding.EncodeToString([]byte(delimited)) diff --git a/internal/services/gateway/action/auth.go b/internal/services/gateway/action/auth.go index 66de2d2..de80de3 100644 --- a/internal/services/gateway/action/auth.go +++ b/internal/services/gateway/action/auth.go @@ -17,12 +17,11 @@ package action import ( "context" + "agola.io/agola/internal/errors" scommon "agola.io/agola/internal/services/common" "agola.io/agola/internal/services/gateway/common" "agola.io/agola/internal/util" cstypes "agola.io/agola/services/configstore/types" - - errors "golang.org/x/xerrors" ) func (h *ActionHandler) IsOrgOwner(ctx context.Context, orgID string) (bool, error) { @@ -38,7 +37,7 @@ func (h *ActionHandler) IsOrgOwner(ctx context.Context, orgID string) (bool, err userOrgs, _, err := h.configstoreClient.GetUserOrgs(ctx, userID) if err != nil { - return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user orgs: %w", err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user orgs")) } for _, userOrg := range userOrgs { @@ -73,7 +72,7 @@ func (h *ActionHandler) IsProjectOwner(ctx context.Context, ownerType cstypes.Co if ownerType == cstypes.ConfigTypeOrg { userOrgs, _, err := h.configstoreClient.GetUserOrgs(ctx, userID) if err != nil { - return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user orgs: %w", err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user orgs")) } for _, userOrg := range userOrgs { @@ -109,7 +108,7 @@ func (h *ActionHandler) IsProjectMember(ctx context.Context, ownerType cstypes.C if ownerType == cstypes.ConfigTypeOrg { userOrgs, _, err := h.configstoreClient.GetUserOrgs(ctx, userID) if err != nil { - return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user orgs: %w", err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user orgs")) } for _, userOrg := range userOrgs { @@ -130,14 +129,14 @@ func (h *ActionHandler) IsVariableOwner(ctx context.Context, parentType cstypes. case cstypes.ConfigTypeProjectGroup: pg, _, err := h.configstoreClient.GetProjectGroup(ctx, parentRef) if err != nil { - return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q: %w", parentRef, err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project group %q", parentRef)) } ownerType = pg.OwnerType ownerID = pg.OwnerID case cstypes.ConfigTypeProject: p, _, err := h.configstoreClient.GetProject(ctx, parentRef) if err != nil { - return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", parentRef, err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q", parentRef)) } ownerType = p.OwnerType ownerID = p.OwnerID @@ -149,7 +148,7 @@ func (h *ActionHandler) IsVariableOwner(ctx context.Context, parentType cstypes. func (h *ActionHandler) CanGetRun(ctx context.Context, runGroup string) (bool, error) { groupType, groupID, err := scommon.GroupTypeIDFromRunGroup(runGroup) if err != nil { - return false, err + return false, errors.WithStack(err) } var visibility cstypes.Visibility @@ -176,7 +175,7 @@ func (h *ActionHandler) CanGetRun(ctx context.Context, runGroup string) (bool, e } isProjectMember, err := h.IsProjectMember(ctx, ownerType, ownerID) if err != nil { - return false, errors.Errorf("failed to determine ownership: %w", err) + return false, errors.Wrapf(err, "failed to determine ownership") } if !isProjectMember { return false, nil @@ -187,7 +186,7 @@ func (h *ActionHandler) CanGetRun(ctx context.Context, runGroup string) (bool, e func (h *ActionHandler) CanDoRunActions(ctx context.Context, runGroup string) (bool, error) { groupType, groupID, err := scommon.GroupTypeIDFromRunGroup(runGroup) if err != nil { - return false, err + return false, errors.WithStack(err) } var ownerType cstypes.ConfigType @@ -208,7 +207,7 @@ func (h *ActionHandler) CanDoRunActions(ctx context.Context, runGroup string) (b isProjectOwner, err := h.IsProjectOwner(ctx, ownerType, ownerID) if err != nil { - return false, errors.Errorf("failed to determine ownership: %w", err) + return false, errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return false, nil diff --git a/internal/services/gateway/action/org.go b/internal/services/gateway/action/org.go index 24fb8df..ee48c69 100644 --- a/internal/services/gateway/action/org.go +++ b/internal/services/gateway/action/org.go @@ -17,11 +17,10 @@ package action import ( "context" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/gateway/common" "agola.io/agola/internal/util" cstypes "agola.io/agola/services/configstore/types" - - errors "golang.org/x/xerrors" ) func (h *ActionHandler) GetOrg(ctx context.Context, orgRef string) (*cstypes.Organization, error) { @@ -110,7 +109,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, req *CreateOrgRequest) (* h.log.Info().Msgf("creating organization") org, _, err := h.configstoreClient.CreateOrg(ctx, org) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create organization: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create organization")) } h.log.Info().Msgf("organization %s created, ID: %s", org.Name, org.ID) @@ -125,14 +124,14 @@ func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { isOrgOwner, err := h.IsOrgOwner(ctx, org.ID) if err != nil { - return errors.Errorf("failed to determine ownership: %w", err) + return errors.Wrapf(err, "failed to determine ownership") } if !isOrgOwner { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } if _, err := h.configstoreClient.DeleteOrg(ctx, orgRef); err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete org: %w", err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to delete org")) } return nil } @@ -155,7 +154,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string isOrgOwner, err := h.IsOrgOwner(ctx, org.ID) if err != nil { - return nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, errors.Wrapf(err, "failed to determine ownership") } if !isOrgOwner { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -163,7 +162,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string orgmember, _, err := h.configstoreClient.AddOrgMember(ctx, orgRef, userRef, role) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to add/update organization member: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to add/update organization member")) } return &AddOrgMemberResponse{ @@ -181,14 +180,14 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str isOrgOwner, err := h.IsOrgOwner(ctx, org.ID) if err != nil { - return errors.Errorf("failed to determine ownership: %w", err) + return errors.Wrapf(err, "failed to determine ownership") } if !isOrgOwner { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } if _, err = h.configstoreClient.RemoveOrgMember(ctx, orgRef, userRef); err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to remove organization member: %w", err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to remove organization member")) } return nil diff --git a/internal/services/gateway/action/project.go b/internal/services/gateway/action/project.go index c5f27d7..eb42876 100644 --- a/internal/services/gateway/action/project.go +++ b/internal/services/gateway/action/project.go @@ -20,25 +20,24 @@ import ( "net/url" "path" + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" "agola.io/agola/internal/services/gateway/common" "agola.io/agola/internal/services/types" "agola.io/agola/internal/util" csapitypes "agola.io/agola/services/configstore/api/types" cstypes "agola.io/agola/services/configstore/types" - - errors "golang.org/x/xerrors" ) func (h *ActionHandler) GetProject(ctx context.Context, projectRef string) (*csapitypes.Project, error) { project, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return nil, err + return nil, errors.WithStack(err) } isProjectMember, err := h.IsProjectMember(ctx, project.OwnerType, project.OwnerID) if err != nil { - return nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, errors.Wrapf(err, "failed to determine ownership") } if project.GlobalVisibility == cstypes.VisibilityPublic { return project, nil @@ -65,7 +64,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq user, _, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", curUserID, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", curUserID)) } parentRef := req.ParentRef if parentRef == "" { @@ -75,12 +74,12 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq pg, _, err := h.configstoreClient.GetProjectGroup(ctx, parentRef) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q: %w", parentRef, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project group %q", parentRef)) } isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID) if err != nil { - return nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -99,7 +98,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq projectPath := path.Join(pg.Path, req.Name) if _, _, err = h.configstoreClient.GetProject(ctx, projectPath); err != nil { if !util.RemoteErrorIs(err, util.ErrNotExist) { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", req.Name, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q", req.Name)) } } else { return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("project %q already exists", projectPath)) @@ -107,7 +106,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName)) } var la *cstypes.LinkedAccount for _, v := range user.LinkedAccounts { @@ -122,18 +121,18 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq gitSource, err := h.GetGitSource(ctx, rs, user.Name, la) if err != nil { - return nil, errors.Errorf("failed to create gitsource client: %w", err) + return nil, errors.Wrapf(err, "failed to create gitsource client") } repo, err := gitSource.GetRepoInfo(req.RepoPath) if err != nil { - return nil, errors.Errorf("failed to get repository info from gitsource: %w", err) + return nil, errors.Wrapf(err, "failed to get repository info from gitsource") } h.log.Info().Msgf("generating ssh key pairs") privateKey, _, err := util.GenSSHKeyPair(4096) if err != nil { - return nil, errors.Errorf("failed to generate ssh key pair: %w", err) + return nil, errors.Wrapf(err, "failed to generate ssh key pair") } p := &cstypes.Project{ @@ -156,7 +155,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq h.log.Info().Msgf("creating project") rp, _, err := h.configstoreClient.CreateProject(ctx, p) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create project: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create project")) } h.log.Info().Msgf("project %s created, ID: %s", rp.Name, rp.ID) @@ -173,7 +172,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq if err := h.cleanupGitSourceRepo(ctx, rs, user, la, rp); err != nil { h.log.Err(err).Msgf("failed to cleanup git source repo") } - return nil, errors.Errorf("failed to setup git source repo: %w", serr) + return nil, errors.Wrapf(serr, "failed to setup git source repo") } return rp, nil @@ -190,12 +189,12 @@ type UpdateProjectRequest struct { func (h *ActionHandler) UpdateProject(ctx context.Context, projectRef string, req *UpdateProjectRequest) (*csapitypes.Project, error) { p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q", projectRef)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) if err != nil { - return nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -217,7 +216,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, projectRef string, re h.log.Info().Msgf("updating project") rp, _, err := h.configstoreClient.UpdateProject(ctx, p.ID, p.Project) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update project: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to update project")) } h.log.Info().Msgf("project %s updated, ID: %s", p.Name, p.ID) @@ -229,17 +228,17 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj user, _, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", curUserID, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", curUserID)) } p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q", projectRef)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) if err != nil { - return nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -247,7 +246,7 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj rs, _, err := h.configstoreClient.GetRemoteSource(ctx, p.RemoteSourceID) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", p.RemoteSourceID, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", p.RemoteSourceID)) } var la *cstypes.LinkedAccount for _, v := range user.LinkedAccounts { @@ -262,13 +261,13 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj gitsource, err := h.GetGitSource(ctx, rs, user.Name, la) if err != nil { - return nil, errors.Errorf("failed to create gitsource client: %w", err) + return nil, errors.Wrapf(err, "failed to create gitsource client") } // check user has access to the repository _, err = gitsource.GetRepoInfo(p.RepositoryPath) if err != nil { - return nil, errors.Errorf("failed to get repository info from gitsource: %w", err) + return nil, errors.Wrapf(err, "failed to get repository info from gitsource") } p.LinkedAccountID = la.ID @@ -276,7 +275,7 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj h.log.Info().Msgf("updating project") rp, _, err := h.configstoreClient.UpdateProject(ctx, p.ID, p.Project) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update project: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to update project")) } h.log.Info().Msgf("project %s updated, ID: %s", p.Name, p.ID) @@ -286,17 +285,17 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj func (h *ActionHandler) setupGitSourceRepo(ctx context.Context, rs *cstypes.RemoteSource, user *cstypes.User, la *cstypes.LinkedAccount, project *csapitypes.Project) error { gitsource, err := h.GetGitSource(ctx, rs, user.Name, la) if err != nil { - return errors.Errorf("failed to create gitsource client: %w", err) + return errors.Wrapf(err, "failed to create gitsource client") } pubKey, err := util.ExtractPublicKey([]byte(project.SSHPrivateKey)) if err != nil { - return errors.Errorf("failed to extract public key: %w", err) + return errors.Wrapf(err, "failed to extract public key") } webhookURL, err := h.genWebhookURL(project) if err != nil { - return errors.Errorf("failed to generate webhook url: %w", err) + return errors.Wrapf(err, "failed to generate webhook url") } // generate deploy keys and webhooks containing the agola project id so we @@ -305,15 +304,15 @@ func (h *ActionHandler) setupGitSourceRepo(ctx context.Context, rs *cstypes.Remo deployKeyName := fmt.Sprintf("agola deploy key - %s", project.ID) h.log.Info().Msgf("creating/updating deploy key: %s", deployKeyName) if err := gitsource.UpdateDeployKey(project.RepositoryPath, deployKeyName, string(pubKey), true); err != nil { - return errors.Errorf("failed to create deploy key: %w", err) + return errors.Wrapf(err, "failed to create deploy key") } h.log.Info().Msgf("deleting existing webhooks") if err := gitsource.DeleteRepoWebhook(project.RepositoryPath, webhookURL); err != nil { - return errors.Errorf("failed to delete repository webhook: %w", err) + return errors.Wrapf(err, "failed to delete repository webhook") } h.log.Info().Msgf("creating webhook to url: %s", webhookURL) if err := gitsource.CreateRepoWebhook(project.RepositoryPath, webhookURL, project.WebhookSecret); err != nil { - return errors.Errorf("failed to create repository webhook: %w", err) + return errors.Wrapf(err, "failed to create repository webhook") } return nil @@ -322,12 +321,12 @@ func (h *ActionHandler) setupGitSourceRepo(ctx context.Context, rs *cstypes.Remo func (h *ActionHandler) cleanupGitSourceRepo(ctx context.Context, rs *cstypes.RemoteSource, user *cstypes.User, la *cstypes.LinkedAccount, project *csapitypes.Project) error { gitsource, err := h.GetGitSource(ctx, rs, user.Name, la) if err != nil { - return errors.Errorf("failed to create gitsource client: %w", err) + return errors.Wrapf(err, "failed to create gitsource client") } webhookURL, err := h.genWebhookURL(project) if err != nil { - return errors.Errorf("failed to generate webhook url: %w", err) + return errors.Wrapf(err, "failed to generate webhook url") } // generate deploy keys and webhooks containing the agola project id so we @@ -336,11 +335,11 @@ func (h *ActionHandler) cleanupGitSourceRepo(ctx context.Context, rs *cstypes.Re deployKeyName := fmt.Sprintf("agola deploy key - %s", project.ID) h.log.Info().Msgf("deleting deploy key: %s", deployKeyName) if err := gitsource.DeleteDeployKey(project.RepositoryPath, deployKeyName); err != nil { - return errors.Errorf("failed to create deploy key: %w", err) + return errors.Wrapf(err, "failed to create deploy key") } h.log.Info().Msgf("deleting existing webhooks") if err := gitsource.DeleteRepoWebhook(project.RepositoryPath, webhookURL); err != nil { - return errors.Errorf("failed to delete repository webhook: %w", err) + return errors.Wrapf(err, "failed to delete repository webhook") } return nil @@ -350,7 +349,7 @@ func (h *ActionHandler) genWebhookURL(project *csapitypes.Project) (string, erro baseWebhookURL := fmt.Sprintf("%s/webhooks", h.apiExposedURL) webhookURL, err := url.Parse(baseWebhookURL) if err != nil { - return "", errors.Errorf("failed to parse base webhook url %q: %w", baseWebhookURL, err) + return "", errors.Wrapf(err, "failed to parse base webhook url %q", baseWebhookURL) } q := url.Values{} q.Add("projectid", project.ID) @@ -363,12 +362,12 @@ func (h *ActionHandler) genWebhookURL(project *csapitypes.Project) (string, erro func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) error { p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q", projectRef)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) if err != nil { - return errors.Errorf("failed to determine ownership: %w", err) + return errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -376,7 +375,7 @@ func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) user, rs, la, err := h.getRemoteRepoAccessData(ctx, p.LinkedAccountID) if err != nil { - return errors.Errorf("failed to get remote repo access data: %w", err) + return errors.Wrapf(err, "failed to get remote repo access data") } // TODO(sgotti) update project repo path if the remote let us query by repository id @@ -387,12 +386,12 @@ func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) error { p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q", projectRef)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) if err != nil { - return errors.Errorf("failed to determine ownership: %w", err) + return errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -429,17 +428,17 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch user, _, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", curUserID, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", curUserID)) } p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q", projectRef)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) if err != nil { - return errors.Errorf("failed to determine ownership: %w", err) + return errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -447,7 +446,7 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch rs, _, err := h.configstoreClient.GetRemoteSource(ctx, p.RemoteSourceID) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", p.RemoteSourceID, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", p.RemoteSourceID)) } var la *cstypes.LinkedAccount for _, v := range user.LinkedAccounts { @@ -462,13 +461,13 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch gitSource, err := h.GetGitSource(ctx, rs, user.Name, la) if err != nil { - return errors.Errorf("failed to create gitsource client: %w", err) + return errors.Wrapf(err, "failed to create gitsource client") } // check user has access to the repository repoInfo, err := gitSource.GetRepoInfo(p.RepositoryPath) if err != nil { - return errors.Errorf("failed to get repository info from gitsource: %w", err) + return errors.Wrapf(err, "failed to get repository info from gitsource") } set := 0 @@ -504,11 +503,11 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch gitRefType, name, err := gitSource.RefType(refName) if err != nil { - return util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to get refType for ref %q: %w", refName, err)) + return util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "failed to get refType for ref %q", refName)) } ref, err := gitSource.GetRef(p.RepositoryPath, refName) if err != nil { - return errors.Errorf("failed to get ref information from git source for ref %q: %w", refName, err) + return errors.Wrapf(err, "failed to get ref information from git source for ref %q", refName) } refCommitSHA = ref.CommitSHA switch gitRefType { @@ -530,7 +529,7 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch commit, err := gitSource.GetCommit(p.RepositoryPath, commitSHA) if err != nil { - return errors.Errorf("failed to get commit information from git source for commit sha %q: %w", commitSHA, err) + return errors.Wrapf(err, "failed to get commit information from git source for commit sha %q", commitSHA) } // use the commit full sha since the user could have provided a short commit sha @@ -585,7 +584,7 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch func (h *ActionHandler) getRemoteRepoAccessData(ctx context.Context, linkedAccountID string) (*cstypes.User, *cstypes.RemoteSource, *cstypes.LinkedAccount, error) { user, _, err := h.configstoreClient.GetUserByLinkedAccount(ctx, linkedAccountID) if err != nil { - return nil, nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user with linked account id %q: %w", linkedAccountID, err)) + return nil, nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user with linked account id %q", linkedAccountID)) } la := user.LinkedAccounts[linkedAccountID] @@ -595,7 +594,7 @@ func (h *ActionHandler) getRemoteRepoAccessData(ctx context.Context, linkedAccou rs, _, err := h.configstoreClient.GetRemoteSource(ctx, la.RemoteSourceID) if err != nil { - return nil, nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, err)) + return nil, nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", la.RemoteSourceID)) } return user, rs, la, nil diff --git a/internal/services/gateway/action/projectgroup.go b/internal/services/gateway/action/projectgroup.go index 56c1499..5ef6486 100644 --- a/internal/services/gateway/action/projectgroup.go +++ b/internal/services/gateway/action/projectgroup.go @@ -18,11 +18,10 @@ import ( "context" "path" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" csapitypes "agola.io/agola/services/configstore/api/types" cstypes "agola.io/agola/services/configstore/types" - - errors "golang.org/x/xerrors" ) func (h *ActionHandler) GetProjectGroup(ctx context.Context, projectGroupRef string) (*csapitypes.ProjectGroup, error) { @@ -63,12 +62,12 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProje pg, _, err := h.configstoreClient.GetProjectGroup(ctx, req.ParentRef) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q: %w", req.ParentRef, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project group %q", req.ParentRef)) } isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID) if err != nil { - return nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -76,7 +75,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProje user, _, err := h.configstoreClient.GetUser(ctx, req.CurrentUserID) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", req.CurrentUserID, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", req.CurrentUserID)) } parentRef := req.ParentRef @@ -97,7 +96,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProje h.log.Info().Msgf("creating projectGroup") rp, _, err := h.configstoreClient.CreateProjectGroup(ctx, p) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create projectGroup: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create projectGroup")) } h.log.Info().Msgf("projectGroup %s created, ID: %s", rp.Name, rp.ID) @@ -114,12 +113,12 @@ type UpdateProjectGroupRequest struct { func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef string, req *UpdateProjectGroupRequest) (*csapitypes.ProjectGroup, error) { pg, _, err := h.configstoreClient.GetProjectGroup(ctx, projectGroupRef) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q: %w", projectGroupRef, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project group %q", projectGroupRef)) } isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID) if err != nil { - return nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -138,7 +137,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef h.log.Info().Msgf("updating project group") rp, _, err := h.configstoreClient.UpdateProjectGroup(ctx, pg.ID, pg.ProjectGroup) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update project group: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to update project group")) } h.log.Info().Msgf("project group %q updated, ID: %s", pg.Name, pg.ID) @@ -148,12 +147,12 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectRef string) error { p, _, err := h.configstoreClient.GetProjectGroup(ctx, projectRef) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q", projectRef)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) if err != nil { - return errors.Errorf("failed to determine ownership: %w", err) + return errors.Wrapf(err, "failed to determine ownership") } if !isProjectOwner { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) diff --git a/internal/services/gateway/action/remotesource.go b/internal/services/gateway/action/remotesource.go index d8e0ecd..4881662 100644 --- a/internal/services/gateway/action/remotesource.go +++ b/internal/services/gateway/action/remotesource.go @@ -17,17 +17,16 @@ package action import ( "context" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/gateway/common" "agola.io/agola/internal/util" cstypes "agola.io/agola/services/configstore/types" - - errors "golang.org/x/xerrors" ) func (h *ActionHandler) GetRemoteSource(ctx context.Context, rsRef string) (*cstypes.RemoteSource, error) { rs, _, err := h.configstoreClient.GetRemoteSource(ctx, rsRef) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return rs, nil } @@ -41,7 +40,7 @@ type GetRemoteSourcesRequest struct { func (h *ActionHandler) GetRemoteSources(ctx context.Context, req *GetRemoteSourcesRequest) ([]*cstypes.RemoteSource, error) { remoteSources, _, err := h.configstoreClient.GetRemoteSources(ctx, req.Start, req.Limit, req.Asc) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return remoteSources, nil } @@ -113,7 +112,7 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, req *CreateRemot h.log.Info().Msgf("creating remotesource") rs, _, err := h.configstoreClient.CreateRemoteSource(ctx, rs) if err != nil { - return nil, errors.Errorf("failed to create remotesource: %w", err) + return nil, errors.Wrapf(err, "failed to create remotesource") } h.log.Info().Msgf("remotesource %s created, ID: %s", rs.Name, rs.ID) @@ -141,7 +140,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceRef) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if req.Name != nil { @@ -175,7 +174,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot h.log.Info().Msgf("updating remotesource") rs, _, err = h.configstoreClient.UpdateRemoteSource(ctx, req.RemoteSourceRef, rs) if err != nil { - return nil, errors.Errorf("failed to update remotesource: %w", err) + return nil, errors.Wrapf(err, "failed to update remotesource") } h.log.Info().Msgf("remotesource %s updated", rs.Name) @@ -188,7 +187,7 @@ func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, rsRef string) er } if _, err := h.configstoreClient.DeleteRemoteSource(ctx, rsRef); err != nil { - return errors.Errorf("failed to delete remote source: %w", err) + return errors.Wrapf(err, "failed to delete remote source") } return nil } diff --git a/internal/services/gateway/action/run.go b/internal/services/gateway/action/run.go index f9e97f4..d05461d 100644 --- a/internal/services/gateway/action/run.go +++ b/internal/services/gateway/action/run.go @@ -22,6 +22,7 @@ import ( "regexp" "agola.io/agola/internal/config" + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" "agola.io/agola/internal/runconfig" scommon "agola.io/agola/internal/services/common" @@ -32,8 +33,6 @@ import ( rsapitypes "agola.io/agola/services/runservice/api/types" rstypes "agola.io/agola/services/runservice/types" "agola.io/agola/services/types" - - errors "golang.org/x/xerrors" ) const ( @@ -80,7 +79,7 @@ func (h *ActionHandler) GetRun(ctx context.Context, runID string) (*rsapitypes.R } canGetRun, err := h.CanGetRun(ctx, runResp.RunConfig.Group) if err != nil { - return nil, errors.Errorf("failed to determine permissions: %w", err) + return nil, errors.Wrapf(err, "failed to determine permissions") } if !canGetRun { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -103,7 +102,7 @@ type GetRunsRequest struct { func (h *ActionHandler) GetRuns(ctx context.Context, req *GetRunsRequest) (*rsapitypes.GetRunsResponse, error) { canGetRun, err := h.CanGetRun(ctx, req.Group) if err != nil { - return nil, errors.Errorf("failed to determine permissions: %w", err) + return nil, errors.Wrapf(err, "failed to determine permissions") } if !canGetRun { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -133,7 +132,7 @@ func (h *ActionHandler) GetLogs(ctx context.Context, req *GetLogsRequest) (*http } canGetRun, err := h.CanGetRun(ctx, runResp.RunConfig.Group) if err != nil { - return nil, errors.Errorf("failed to determine permissions: %w", err) + return nil, errors.Wrapf(err, "failed to determine permissions") } if !canGetRun { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -161,7 +160,7 @@ func (h *ActionHandler) DeleteLogs(ctx context.Context, req *DeleteLogsRequest) } canDoRunActions, err := h.CanDoRunActions(ctx, runResp.RunConfig.Group) if err != nil { - return errors.Errorf("failed to determine permissions: %w", err) + return errors.Wrapf(err, "failed to determine permissions") } if !canDoRunActions { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -197,7 +196,7 @@ func (h *ActionHandler) RunAction(ctx context.Context, req *RunActionsRequest) ( } canGetRun, err := h.CanDoRunActions(ctx, runResp.RunConfig.Group) if err != nil { - return nil, errors.Errorf("failed to determine permissions: %w", err) + return nil, errors.Wrapf(err, "failed to determine permissions") } if !canGetRun { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -261,7 +260,7 @@ func (h *ActionHandler) RunTaskAction(ctx context.Context, req *RunTaskActionsRe } canDoRunAction, err := h.CanDoRunActions(ctx, runResp.RunConfig.Group) if err != nil { - return errors.Errorf("failed to determine permissions: %w", err) + return errors.Wrapf(err, "failed to determine permissions") } if !canDoRunAction { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -286,7 +285,7 @@ func (h *ActionHandler) RunTaskAction(ctx context.Context, req *RunTaskActionsRe approversAnnotation, ok := annotations[scommon.ApproversAnnotation] if ok { if err := json.Unmarshal([]byte(approversAnnotation), &approvers); err != nil { - return errors.Errorf("failed to unmarshal run task approvers annotation: %w", err) + return errors.Wrapf(err, "failed to unmarshal run task approvers annotation") } } @@ -299,7 +298,7 @@ func (h *ActionHandler) RunTaskAction(ctx context.Context, req *RunTaskActionsRe approversj, err := json.Marshal(approvers) if err != nil { - return errors.Errorf("failed to marshal run task approvers annotation: %w", err) + return errors.Wrapf(err, "failed to marshal run task approvers annotation") } annotations[scommon.ApproversAnnotation] = string(approversj) @@ -398,7 +397,7 @@ func (h *ActionHandler) CreateRuns(ctx context.Context, req *CreateRunRequest) e gitURL, err := util.ParseGitURL(req.CloneURL) if err != nil { - return errors.Errorf("failed to parse clone url: %w", err) + return errors.Wrapf(err, "failed to parse clone url") } gitHost := gitURL.Hostname() gitPort := gitURL.Port() @@ -434,7 +433,7 @@ func (h *ActionHandler) CreateRuns(ctx context.Context, req *CreateRunRequest) e var err error variables, err = h.genRunVariables(ctx, req) if err != nil { - return err + return errors.WithStack(err) } } } else { @@ -481,7 +480,7 @@ func (h *ActionHandler) CreateRuns(ctx context.Context, req *CreateRunRequest) e data, filename, err := h.fetchConfigFiles(ctx, req.GitSource, req.RepoPath, req.CommitSHA) if err != nil { - return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to fetch config file: %w", err)) + return util.NewAPIError(util.ErrInternal, errors.Wrapf(err, "failed to fetch config file")) } h.log.Debug().Msgf("data: %s", data) @@ -577,7 +576,7 @@ func (h *ActionHandler) fetchConfigFiles(ctx context.Context, gitSource gitsourc return false, nil }) if err != nil { - return nil, "", err + return nil, "", errors.WithStack(err) } return data, filename, nil } @@ -588,7 +587,7 @@ func (h *ActionHandler) genRunVariables(ctx context.Context, req *CreateRunReque // get project variables pvars, _, err := h.configstoreClient.GetProjectVariables(ctx, req.Project.ID, true) if err != nil { - return nil, errors.Errorf("failed to get project variables: %w", err) + return nil, errors.Wrapf(err, "failed to get project variables") } // remove overriden variables @@ -597,7 +596,7 @@ func (h *ActionHandler) genRunVariables(ctx context.Context, req *CreateRunReque // get project secrets secrets, _, err := h.configstoreClient.GetProjectSecrets(ctx, req.Project.ID, true) if err != nil { - return nil, errors.Errorf("failed to get project secrets: %w", err) + return nil, errors.Wrapf(err, "failed to get project secrets") } for _, pvar := range pvars { // find the value match diff --git a/internal/services/gateway/action/secret.go b/internal/services/gateway/action/secret.go index 615f4e6..d44ff6c 100644 --- a/internal/services/gateway/action/secret.go +++ b/internal/services/gateway/action/secret.go @@ -17,12 +17,11 @@ package action import ( "context" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/common" "agola.io/agola/internal/util" csapitypes "agola.io/agola/services/configstore/api/types" cstypes "agola.io/agola/services/configstore/types" - - errors "golang.org/x/xerrors" ) type GetSecretsRequest struct { @@ -73,7 +72,7 @@ type CreateSecretRequest struct { func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretRequest) (*csapitypes.Secret, error) { isVariableOwner, err := h.IsVariableOwner(ctx, req.ParentType, req.ParentRef) if err != nil { - return nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, errors.Wrapf(err, "failed to determine ownership") } if !isVariableOwner { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -99,7 +98,7 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretReque rs, _, err = h.configstoreClient.CreateProjectSecret(ctx, req.ParentRef, s) } if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create secret: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create secret")) } h.log.Info().Msgf("secret %s created, ID: %s", rs.Name, rs.ID) @@ -127,7 +126,7 @@ type UpdateSecretRequest struct { func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretRequest) (*csapitypes.Secret, error) { isVariableOwner, err := h.IsVariableOwner(ctx, req.ParentType, req.ParentRef) if err != nil { - return nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, errors.Wrapf(err, "failed to determine ownership") } if !isVariableOwner { return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -153,7 +152,7 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque rs, _, err = h.configstoreClient.UpdateProjectSecret(ctx, req.ParentRef, req.SecretName, s) } if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update secret: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to update secret")) } h.log.Info().Msgf("secret %s updated, ID: %s", rs.Name, rs.ID) @@ -163,7 +162,7 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType cstypes.ConfigType, parentRef, name string) error { isVariableOwner, err := h.IsVariableOwner(ctx, parentType, parentRef) if err != nil { - return errors.Errorf("failed to determine ownership: %w", err) + return errors.Wrapf(err, "failed to determine ownership") } if !isVariableOwner { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -178,7 +177,7 @@ func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType cstypes.Con _, err = h.configstoreClient.DeleteProjectSecret(ctx, parentRef, name) } if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete secret: %w", err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to delete secret")) } return nil } diff --git a/internal/services/gateway/action/user.go b/internal/services/gateway/action/user.go index 4e8bca3..86496ae 100644 --- a/internal/services/gateway/action/user.go +++ b/internal/services/gateway/action/user.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" "agola.io/agola/internal/gitsources/agolagit" scommon "agola.io/agola/internal/services/common" @@ -32,7 +33,6 @@ import ( cstypes "agola.io/agola/services/configstore/types" "github.com/golang-jwt/jwt/v4" - errors "golang.org/x/xerrors" ) const ( @@ -111,7 +111,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) h.log.Info().Msgf("creating user") u, _, err := h.configstoreClient.CreateUser(ctx, creq) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create user: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create user")) } h.log.Info().Msgf("user %s created, ID: %s", u.Name, u.ID) @@ -130,7 +130,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, req *CreateUserToke userRef := req.UserRef user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return "", util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user: %w", err)) + return "", util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user")) } // only admin or the same logged user can create a token @@ -147,7 +147,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, req *CreateUserToke } res, _, err := h.configstoreClient.CreateUserToken(ctx, userRef, creq) if err != nil { - return "", util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create user token: %w", err)) + return "", util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create user token")) } h.log.Info().Msgf("token %q for user %q created", req.TokenName, userRef) @@ -168,11 +168,11 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque userRef := req.UserRef user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", userRef, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", userRef)) } rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName)) } var la *cstypes.LinkedAccount for _, v := range user.LinkedAccounts { @@ -187,16 +187,16 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque accessToken, err := scommon.GetAccessToken(rs, req.UserAccessToken, req.Oauth2AccessToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } userSource, err := scommon.GetUserSource(rs, accessToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } remoteUserInfo, err := userSource.GetUserInfo() if err != nil { - return nil, errors.Errorf("failed to retrieve remote user info for remote source %q: %w", rs.ID, err) + return nil, errors.Wrapf(err, "failed to retrieve remote user info for remote source %q", rs.ID) } if remoteUserInfo.ID == "" { return nil, errors.Errorf("empty remote user id for remote source %q", rs.ID) @@ -215,7 +215,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque h.log.Info().Msgf("creating linked account") la, _, err = h.configstoreClient.CreateUserLA(ctx, userRef, creq) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create linked account: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create linked account")) } h.log.Info().Msgf("linked account %q for user %q created", la.ID, userRef) @@ -225,7 +225,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque func (h *ActionHandler) UpdateUserLA(ctx context.Context, userRef string, la *cstypes.LinkedAccount) error { user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", userRef, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", userRef)) } laFound := false for _, ula := range user.LinkedAccounts { @@ -250,7 +250,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, userRef string, la *cs h.log.Info().Msgf("updating user %q linked account", userRef) la, _, err = h.configstoreClient.UpdateUserLA(ctx, userRef, la.ID, creq) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update user: %w", err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to update user")) } h.log.Info().Msgf("linked account %q for user %q updated", la.ID, userRef) @@ -265,11 +265,11 @@ func (h *ActionHandler) RefreshLinkedAccount(ctx context.Context, rs *cstypes.Re if isAccessTokenExpired(la.Oauth2AccessTokenExpiresAt) { userSource, err := scommon.GetOauth2Source(rs, "") if err != nil { - return nil, err + return nil, errors.WithStack(err) } token, err := userSource.RefreshOauth2Token(la.Oauth2RefreshToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if la.Oauth2AccessToken != token.AccessToken { @@ -278,7 +278,7 @@ func (h *ActionHandler) RefreshLinkedAccount(ctx context.Context, rs *cstypes.Re la.Oauth2AccessTokenExpiresAt = token.Expiry if err := h.UpdateUserLA(ctx, userName, la); err != nil { - return nil, errors.Errorf("failed to update linked account: %w", err) + return nil, errors.Wrapf(err, "failed to update linked account") } } } @@ -291,9 +291,10 @@ func (h *ActionHandler) RefreshLinkedAccount(ctx context.Context, rs *cstypes.Re func (h *ActionHandler) GetGitSource(ctx context.Context, rs *cstypes.RemoteSource, userName string, la *cstypes.LinkedAccount) (gitsource.GitSource, error) { la, err := h.RefreshLinkedAccount(ctx, rs, userName, la) if err != nil { - return nil, err + return nil, errors.WithStack(err) } - return scommon.GetGitSource(rs, la) + gs, err := scommon.GetGitSource(rs, la) + return gs, errors.WithStack(err) } type RegisterUserRequest struct { @@ -315,7 +316,7 @@ func (h *ActionHandler) RegisterUser(ctx context.Context, req *RegisterUserReque rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName)) } if !*rs.RegistrationEnabled { return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source user registration is disabled")) @@ -323,16 +324,16 @@ func (h *ActionHandler) RegisterUser(ctx context.Context, req *RegisterUserReque accessToken, err := scommon.GetAccessToken(rs, req.UserAccessToken, req.Oauth2AccessToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } userSource, err := scommon.GetUserSource(rs, accessToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } remoteUserInfo, err := userSource.GetUserInfo() if err != nil { - return nil, errors.Errorf("failed to retrieve remote user info for remote source %q: %w", rs.ID, err) + return nil, errors.Wrapf(err, "failed to retrieve remote user info for remote source %q", rs.ID) } if remoteUserInfo.ID == "" { return nil, errors.Errorf("empty remote user id for remote source %q", rs.ID) @@ -354,7 +355,7 @@ func (h *ActionHandler) RegisterUser(ctx context.Context, req *RegisterUserReque h.log.Info().Msgf("creating user account") u, _, err := h.configstoreClient.CreateUser(ctx, creq) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create linked account: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create linked account")) } h.log.Info().Msgf("user %q created", req.UserName) @@ -377,7 +378,7 @@ type LoginUserResponse struct { func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (*LoginUserResponse, error) { rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName)) } if !*rs.LoginEnabled { return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source user login is disabled")) @@ -385,16 +386,16 @@ func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (* accessToken, err := scommon.GetAccessToken(rs, req.UserAccessToken, req.Oauth2AccessToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } userSource, err := scommon.GetUserSource(rs, accessToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } remoteUserInfo, err := userSource.GetUserInfo() if err != nil { - return nil, errors.Errorf("failed to retrieve remote user info for remote source %q: %w", rs.ID, err) + return nil, errors.Wrapf(err, "failed to retrieve remote user info for remote source %q", rs.ID) } if remoteUserInfo.ID == "" { return nil, errors.Errorf("empty remote user id for remote source %q", rs.ID) @@ -402,7 +403,7 @@ func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (* user, _, err := h.configstoreClient.GetUserByLinkedAccountRemoteUserAndSource(ctx, remoteUserInfo.ID, rs.ID) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user for remote user id %q and remote source %q: %w", remoteUserInfo.ID, rs.ID, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user for remote user id %q and remote source %q", remoteUserInfo.ID, rs.ID)) } var la *cstypes.LinkedAccount @@ -437,7 +438,7 @@ func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (* h.log.Info().Msgf("updating user %q linked account", user.Name) la, _, err = h.configstoreClient.UpdateUserLA(ctx, user.Name, la.ID, creq) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update user: %w", err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to update user")) } h.log.Info().Msgf("linked account %q for user %q updated", la.ID, user.Name) } @@ -445,7 +446,7 @@ func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (* // generate jwt token token, err := scommon.GenerateLoginJWTToken(h.sd, user.ID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &LoginUserResponse{ Token: token, @@ -469,21 +470,21 @@ type AuthorizeResponse struct { func (h *ActionHandler) Authorize(ctx context.Context, req *AuthorizeRequest) (*AuthorizeResponse, error) { rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName)) } accessToken, err := scommon.GetAccessToken(rs, req.UserAccessToken, req.Oauth2AccessToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } userSource, err := scommon.GetUserSource(rs, accessToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } remoteUserInfo, err := userSource.GetUserInfo() if err != nil { - return nil, errors.Errorf("failed to retrieve remote user info for remote source %q: %w", rs.ID, err) + return nil, errors.Wrapf(err, "failed to retrieve remote user info for remote source %q", rs.ID) } if remoteUserInfo.ID == "" { return nil, errors.Errorf("empty remote user id for remote source %q", rs.ID) @@ -503,7 +504,7 @@ type RemoteSourceAuthResponse struct { func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSourceName, loginName, loginPassword string, requestType RemoteSourceRequestType, req interface{}) (*RemoteSourceAuthResponse, error) { rs, _, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceName) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", remoteSourceName, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", remoteSourceName)) } switch requestType { @@ -512,7 +513,7 @@ func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSource user, _, err := h.configstoreClient.GetUser(ctx, req.UserRef) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", req.UserRef, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", req.UserRef)) } curUserID := common.CurrentUserID(ctx) @@ -548,15 +549,15 @@ func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSource case cstypes.RemoteSourceAuthTypeOauth2: oauth2Source, err := scommon.GetOauth2Source(rs, "") if err != nil { - return nil, errors.Errorf("failed to create git source: %w", err) + return nil, errors.Wrapf(err, "failed to create git source") } token, err := scommon.GenerateOauth2JWTToken(h.sd, rs.Name, string(requestType), req) if err != nil { - return nil, err + return nil, errors.WithStack(err) } redirect, err := oauth2Source.GetOauth2AuthorizationURL(h.webExposedURL+"/oauth2/callback", token) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &RemoteSourceAuthResponse{ @@ -566,23 +567,23 @@ func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSource case cstypes.RemoteSourceAuthTypePassword: passwordSource, err := scommon.GetPasswordSource(rs, "") if err != nil { - return nil, errors.Errorf("failed to create git source: %w", err) + return nil, errors.Wrapf(err, "failed to create git source") } tokenName := "agola-" + h.agolaID accessToken, err := passwordSource.LoginPassword(loginName, loginPassword, tokenName) if err != nil { if errors.Is(err, gitsource.ErrUnauthorized) { - return nil, util.NewAPIError(util.ErrUnauthorized, errors.Errorf("failed to login to remotesource %q: %w", remoteSourceName, err)) + return nil, util.NewAPIError(util.ErrUnauthorized, errors.Wrapf(err, "failed to login to remotesource %q", remoteSourceName)) } - return nil, errors.Errorf("failed to login to remote source %q with login name %q: %w", rs.Name, loginName, err) + return nil, errors.Wrapf(err, "failed to login to remote source %q with login name %q", rs.Name, loginName) } requestj, err := json.Marshal(req) if err != nil { - return nil, err + return nil, errors.WithStack(err) } cres, err := h.HandleRemoteSourceAuthRequest(ctx, requestType, string(requestj), accessToken, "", "", time.Time{}) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &RemoteSourceAuthResponse{ Response: cres.Response, @@ -629,7 +630,7 @@ func (h *ActionHandler) HandleRemoteSourceAuthRequest(ctx context.Context, reque } la, err := h.CreateUserLA(ctx, creq) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &RemoteSourceAuthResult{ RequestType: requestType, @@ -654,7 +655,7 @@ func (h *ActionHandler) HandleRemoteSourceAuthRequest(ctx context.Context, reque } cresp, err := h.RegisterUser(ctx, creq) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &RemoteSourceAuthResult{ RequestType: requestType, @@ -676,7 +677,7 @@ func (h *ActionHandler) HandleRemoteSourceAuthRequest(ctx context.Context, reque } cresp, err := h.LoginUser(ctx, creq) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &RemoteSourceAuthResult{ RequestType: requestType, @@ -698,7 +699,7 @@ func (h *ActionHandler) HandleRemoteSourceAuthRequest(ctx context.Context, reque } cresp, err := h.Authorize(ctx, creq) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &RemoteSourceAuthResult{ RequestType: requestType, @@ -727,7 +728,7 @@ func (h *ActionHandler) HandleOauth2Callback(ctx context.Context, code, state st return key, nil }) if err != nil { - return nil, errors.Errorf("failed to parse jwt: %w", err) + return nil, errors.Wrapf(err, "failed to parse jwt") } if !token.Valid { return nil, errors.Errorf("invalid token") @@ -740,17 +741,17 @@ func (h *ActionHandler) HandleOauth2Callback(ctx context.Context, code, state st rs, _, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceName) if err != nil { - return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", remoteSourceName, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get remote source %q", remoteSourceName)) } oauth2Source, err := scommon.GetOauth2Source(rs, "") if err != nil { - return nil, errors.Errorf("failed to create oauth2 source: %w", err) + return nil, errors.Wrapf(err, "failed to create oauth2 source") } oauth2Token, err := oauth2Source.RequestOauth2Token(h.webExposedURL+"/oauth2/callback", code) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return h.HandleRemoteSourceAuthRequest(ctx, requestType, requestString, "", oauth2Token.AccessToken, oauth2Token.RefreshToken, oauth2Token.Expiry) @@ -762,7 +763,7 @@ func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error { } if _, err := h.configstoreClient.DeleteUser(ctx, userRef); err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete user: %w", err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to delete user")) } return nil } @@ -777,7 +778,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", userRef, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", userRef)) } // only admin or the same logged user can create a token @@ -786,7 +787,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) } if _, err = h.configstoreClient.DeleteUserLA(ctx, userRef, laID); err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete user linked account: %w", err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to delete user linked account")) } return nil } @@ -801,7 +802,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", userRef, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", userRef)) } // only admin or the same logged user can create a token @@ -810,7 +811,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName } if _, err = h.configstoreClient.DeleteUserToken(ctx, userRef, tokenName); err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete user token: %w", err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to delete user token")) } return nil } @@ -833,7 +834,7 @@ func (h *ActionHandler) UserCreateRun(ctx context.Context, req *UserCreateRunReq for _, res := range req.PullRequestRefRegexes { re, err := regexp.Compile(res) if err != nil { - return fmt.Errorf("wrong regular expression %q: %w", res, err) + return errors.Wrapf(err, "wrong regular expression %q", res) } prRefRegexes = append(prRefRegexes, re) } @@ -842,7 +843,7 @@ func (h *ActionHandler) UserCreateRun(ctx context.Context, req *UserCreateRunReq user, _, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", curUserID, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get user %q", curUserID)) } // Verify that the repo is owned by the user @@ -892,7 +893,7 @@ func (h *ActionHandler) UserCreateRun(ctx context.Context, req *UserCreateRunReq gitRefType, name, err := gitSource.RefType(ref) if err != nil { - return util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to get refType for ref %q: %w", ref, err)) + return util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "failed to get refType for ref %q", ref)) } var pullRequestID string diff --git a/internal/services/gateway/action/variable.go b/internal/services/gateway/action/variable.go index 90b9d4d..cd76799 100644 --- a/internal/services/gateway/action/variable.go +++ b/internal/services/gateway/action/variable.go @@ -17,11 +17,11 @@ package action import ( "context" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/common" "agola.io/agola/internal/util" csapitypes "agola.io/agola/services/configstore/api/types" cstypes "agola.io/agola/services/configstore/types" - errors "golang.org/x/xerrors" ) type GetVariablesRequest struct { @@ -79,7 +79,7 @@ type CreateVariableRequest struct { func (h *ActionHandler) CreateVariable(ctx context.Context, req *CreateVariableRequest) (*csapitypes.Variable, []*csapitypes.Secret, error) { isVariableOwner, err := h.IsVariableOwner(ctx, req.ParentType, req.ParentRef) if err != nil { - return nil, nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, nil, errors.Wrapf(err, "failed to determine ownership") } if !isVariableOwner { return nil, nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -110,25 +110,25 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, req *CreateVariableR var err error cssecrets, _, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q secrets: %w", req.ParentRef, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project group %q secrets", req.ParentRef)) } h.log.Info().Msgf("creating project group variable") rv, _, err = h.configstoreClient.CreateProjectGroupVariable(ctx, req.ParentRef, v) if err != nil { - return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create variable: %w", err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create variable")) } case cstypes.ConfigTypeProject: var err error cssecrets, _, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q secrets: %w", req.ParentRef, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q secrets", req.ParentRef)) } h.log.Info().Msgf("creating project variable") rv, _, err = h.configstoreClient.CreateProjectVariable(ctx, req.ParentRef, v) if err != nil { - return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create variable: %w", err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create variable")) } } h.log.Info().Msgf("variable %s created, ID: %s", rv.Name, rv.ID) @@ -150,7 +150,7 @@ type UpdateVariableRequest struct { func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableRequest) (*csapitypes.Variable, []*csapitypes.Secret, error) { isVariableOwner, err := h.IsVariableOwner(ctx, req.ParentType, req.ParentRef) if err != nil { - return nil, nil, errors.Errorf("failed to determine ownership: %w", err) + return nil, nil, errors.Wrapf(err, "failed to determine ownership") } if !isVariableOwner { return nil, nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -181,25 +181,25 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR var err error cssecrets, _, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q secrets: %w", req.ParentRef, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project group %q secrets", req.ParentRef)) } h.log.Info().Msgf("creating project group variable") rv, _, err = h.configstoreClient.UpdateProjectGroupVariable(ctx, req.ParentRef, req.VariableName, v) if err != nil { - return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create variable: %w", err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create variable")) } case cstypes.ConfigTypeProject: var err error cssecrets, _, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q secrets: %w", req.ParentRef, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to get project %q secrets", req.ParentRef)) } h.log.Info().Msgf("creating project variable") rv, _, err = h.configstoreClient.UpdateProjectVariable(ctx, req.ParentRef, req.VariableName, v) if err != nil { - return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create variable: %w", err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to create variable")) } } h.log.Info().Msgf("variable %s created, ID: %s", rv.Name, rv.ID) @@ -210,7 +210,7 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType cstypes.ConfigType, parentRef, name string) error { isVariableOwner, err := h.IsVariableOwner(ctx, parentType, parentRef) if err != nil { - return errors.Errorf("failed to determine ownership: %w", err) + return errors.Wrapf(err, "failed to determine ownership") } if !isVariableOwner { return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) @@ -225,7 +225,7 @@ func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType cstypes.C _, err = h.configstoreClient.DeleteProjectVariable(ctx, parentRef, name) } if err != nil { - return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete variable: %w", err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Wrapf(err, "failed to delete variable")) } return nil } diff --git a/internal/services/gateway/api/api.go b/internal/services/gateway/api/api.go index 12ee108..3a727ca 100644 --- a/internal/services/gateway/api/api.go +++ b/internal/services/gateway/api/api.go @@ -18,18 +18,18 @@ import ( "net/http" "net/url" + "agola.io/agola/internal/errors" util "agola.io/agola/internal/util" cstypes "agola.io/agola/services/configstore/types" "github.com/gorilla/mux" - errors "golang.org/x/xerrors" ) func GetConfigTypeRef(r *http.Request) (cstypes.ConfigType, string, error) { vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong projectref %q: %w", vars["projectref"], err)) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "wrong projectref %q", vars["projectref"])) } if projectRef != "" { return cstypes.ConfigTypeProject, projectRef, nil @@ -37,7 +37,7 @@ func GetConfigTypeRef(r *http.Request) (cstypes.ConfigType, string, error) { projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong projectgroupref %q: %w", vars["projectgroupref"], err)) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "wrong projectgroupref %q", vars["projectgroupref"])) } if projectGroupRef != "" { return cstypes.ConfigTypeProjectGroup, projectGroupRef, nil diff --git a/internal/services/gateway/api/org.go b/internal/services/gateway/api/org.go index e1cc082..459bcac 100644 --- a/internal/services/gateway/api/org.go +++ b/internal/services/gateway/api/org.go @@ -19,12 +19,12 @@ import ( "net/http" "strconv" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/gateway/action" "agola.io/agola/internal/services/gateway/common" "agola.io/agola/internal/util" cstypes "agola.io/agola/services/configstore/types" gwapitypes "agola.io/agola/services/gateway/api/types" - errors "golang.org/x/xerrors" "github.com/gorilla/mux" "github.com/rs/zerolog" @@ -148,7 +148,7 @@ func (h *OrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "cannot parse limit"))) return } } diff --git a/internal/services/gateway/api/projectgroup.go b/internal/services/gateway/api/projectgroup.go index 87fdde4..b4c9cc6 100644 --- a/internal/services/gateway/api/projectgroup.go +++ b/internal/services/gateway/api/projectgroup.go @@ -19,13 +19,13 @@ import ( "net/http" "net/url" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/gateway/action" "agola.io/agola/internal/services/gateway/common" "agola.io/agola/internal/util" csapitypes "agola.io/agola/services/configstore/api/types" cstypes "agola.io/agola/services/configstore/types" gwapitypes "agola.io/agola/services/gateway/api/types" - errors "golang.org/x/xerrors" "github.com/gorilla/mux" "github.com/rs/zerolog" diff --git a/internal/services/gateway/api/remoterepo.go b/internal/services/gateway/api/remoterepo.go index 60c2570..570768f 100644 --- a/internal/services/gateway/api/remoterepo.go +++ b/internal/services/gateway/api/remoterepo.go @@ -17,6 +17,7 @@ package api import ( "net/http" + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" "agola.io/agola/internal/services/gateway/action" "agola.io/agola/internal/services/gateway/common" @@ -27,7 +28,6 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) func createRemoteRepoResponse(r *gitsource.RepoInfo) *gwapitypes.RemoteRepoResponse { @@ -95,7 +95,7 @@ func (h *UserRemoteReposHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques remoteRepos, err := gitsource.ListUserRepos() if err != nil { - err := util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to get user repositories from git source: %w", err)) + err := util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "failed to get user repositories from git source")) util.HTTPError(w, err) h.log.Err(err).Send() return diff --git a/internal/services/gateway/api/remotesource.go b/internal/services/gateway/api/remotesource.go index 3276fb3..e7ce171 100644 --- a/internal/services/gateway/api/remotesource.go +++ b/internal/services/gateway/api/remotesource.go @@ -19,6 +19,7 @@ import ( "net/http" "strconv" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/gateway/action" "agola.io/agola/internal/util" cstypes "agola.io/agola/services/configstore/types" @@ -26,7 +27,6 @@ import ( "github.com/rs/zerolog" "github.com/gorilla/mux" - errors "golang.org/x/xerrors" ) type CreateRemoteSourceHandler struct { @@ -175,7 +175,7 @@ func (h *RemoteSourcesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var err error limit, err = strconv.Atoi(limitS) if err != nil { - util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "cannot parse limit"))) return } } diff --git a/internal/services/gateway/api/run.go b/internal/services/gateway/api/run.go index a86c8b5..b3ae092 100644 --- a/internal/services/gateway/api/run.go +++ b/internal/services/gateway/api/run.go @@ -20,6 +20,7 @@ import ( "net/http" "strconv" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/gateway/action" "agola.io/agola/internal/util" gwapitypes "agola.io/agola/services/gateway/api/types" @@ -27,7 +28,6 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) func createRunResponse(r *rstypes.Run, rc *rstypes.RunConfig) *gwapitypes.RunResponse { @@ -269,7 +269,7 @@ func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "cannot parse limit"))) return } } @@ -427,7 +427,7 @@ func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error step, err = strconv.Atoi(stepStr) if err != nil { - util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse step number: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "cannot parse step number"))) return } } @@ -487,7 +487,7 @@ func sendLogs(w io.Writer, r io.Reader) error { n, err := r.Read(buf) if err != nil { if err != io.EOF { - return err + return errors.WithStack(err) } if n == 0 { return nil @@ -495,7 +495,7 @@ func sendLogs(w io.Writer, r io.Reader) error { stop = true } if _, err := w.Write(buf[:n]); err != nil { - return err + return errors.WithStack(err) } if flusher != nil { flusher.Flush() @@ -544,7 +544,7 @@ func (h *LogsDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error step, err = strconv.Atoi(stepStr) if err != nil { - util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse step number: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "cannot parse step number"))) return } } diff --git a/internal/services/gateway/api/user.go b/internal/services/gateway/api/user.go index c64720c..9f6aedf 100644 --- a/internal/services/gateway/api/user.go +++ b/internal/services/gateway/api/user.go @@ -21,6 +21,7 @@ import ( "sort" "strconv" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/gateway/action" "agola.io/agola/internal/services/gateway/common" "agola.io/agola/internal/util" @@ -30,7 +31,6 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) type CreateUserHandler struct { @@ -193,7 +193,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "cannot parse limit"))) return } } @@ -273,7 +273,7 @@ func (h *CreateUserLAHandler) createUserLA(ctx context.Context, userRef string, h.log.Info().Msgf("creating linked account") cresp, err := h.ah.HandleRemoteSourceAuth(ctx, req.RemoteSourceName, req.RemoteSourceLoginName, req.RemoteSourceLoginPassword, action.RemoteSourceRequestTypeCreateUserLA, creq) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if cresp.Oauth2Redirect != "" { return &gwapitypes.CreateUserLAResponse{ @@ -427,7 +427,7 @@ func (h *RegisterUserHandler) registerUser(ctx context.Context, req *gwapitypes. cresp, err := h.ah.HandleRemoteSourceAuth(ctx, req.CreateUserLARequest.RemoteSourceName, req.CreateUserLARequest.RemoteSourceLoginName, req.CreateUserLARequest.RemoteSourceLoginPassword, action.RemoteSourceRequestTypeRegisterUser, creq) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if cresp.Oauth2Redirect != "" { return &gwapitypes.RegisterUserResponse{ @@ -477,7 +477,7 @@ func (h *AuthorizeHandler) authorize(ctx context.Context, req *gwapitypes.LoginU cresp, err := h.ah.HandleRemoteSourceAuth(ctx, req.RemoteSourceName, req.LoginName, req.LoginPassword, action.RemoteSourceRequestTypeAuthorize, creq) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if cresp.Oauth2Redirect != "" { return &gwapitypes.AuthorizeResponse{ @@ -535,7 +535,7 @@ func (h *LoginUserHandler) loginUser(ctx context.Context, req *gwapitypes.LoginU h.log.Info().Msgf("logging in user") cresp, err := h.ah.HandleRemoteSourceAuth(ctx, req.RemoteSourceName, req.LoginName, req.LoginPassword, action.RemoteSourceRequestTypeLoginUser, creq) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if cresp.Oauth2Redirect != "" { return &gwapitypes.LoginUserResponse{ diff --git a/internal/services/gateway/api/webhook.go b/internal/services/gateway/api/webhook.go index f17e1a6..af00ba9 100644 --- a/internal/services/gateway/api/webhook.go +++ b/internal/services/gateway/api/webhook.go @@ -17,6 +17,7 @@ package api import ( "net/http" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/common" "agola.io/agola/internal/services/gateway/action" "agola.io/agola/internal/services/types" @@ -25,7 +26,6 @@ import ( rsclient "agola.io/agola/services/runservice/client" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) type webhooksHandler struct { @@ -70,13 +70,13 @@ func (h *webhooksHandler) handleWebhook(r *http.Request) error { csProject, _, err := h.configstoreClient.GetProject(ctx, projectID) if err != nil { - return util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to get project %s: %w", projectID, err)) + return util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "failed to get project %s", projectID)) } project := csProject.Project user, _, err := h.configstoreClient.GetUserByLinkedAccount(ctx, project.LinkedAccountID) if err != nil { - return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to get user by linked account %q: %w", project.LinkedAccountID, err)) + return util.NewAPIError(util.ErrInternal, errors.Wrapf(err, "failed to get user by linked account %q", project.LinkedAccountID)) } la := user.LinkedAccounts[project.LinkedAccountID] if la == nil { @@ -84,12 +84,12 @@ func (h *webhooksHandler) handleWebhook(r *http.Request) error { } rs, _, err := h.configstoreClient.GetRemoteSource(ctx, la.RemoteSourceID) if err != nil { - return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, err)) + return util.NewAPIError(util.ErrInternal, errors.Wrapf(err, "failed to get remote source %q", la.RemoteSourceID)) } gitSource, err := h.ah.GetGitSource(ctx, rs, user.Name, la) if err != nil { - return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to create gitea client: %w", err)) + return util.NewAPIError(util.ErrInternal, errors.Wrapf(err, "failed to create gitea client")) } sshPrivKey := project.SSHPrivateKey @@ -102,7 +102,7 @@ func (h *webhooksHandler) handleWebhook(r *http.Request) error { webhookData, err := gitSource.ParseWebhook(r, project.WebhookSecret) if err != nil { - return util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to parse webhook: %w", err)) + return util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "failed to parse webhook")) } // skip nil webhook data // TODO(sgotti) report the reason of the skip @@ -141,7 +141,7 @@ func (h *webhooksHandler) handleWebhook(r *http.Request) error { CompareLink: webhookData.CompareLink, } if err := h.ah.CreateRuns(ctx, req); err != nil { - return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to create run: %w", err)) + return util.NewAPIError(util.ErrInternal, errors.Wrapf(err, "failed to create run")) } return nil diff --git a/internal/services/gateway/gateway.go b/internal/services/gateway/gateway.go index 81bacd7..5c01916 100644 --- a/internal/services/gateway/gateway.go +++ b/internal/services/gateway/gateway.go @@ -21,6 +21,7 @@ import ( "net/http" scommon "agola.io/agola/internal/common" + "agola.io/agola/internal/errors" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/services/common" "agola.io/agola/internal/services/config" @@ -36,7 +37,6 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - errors "golang.org/x/xerrors" ) const ( @@ -93,19 +93,19 @@ func NewGateway(ctx context.Context, log zerolog.Logger, gc *config.Config) (*Ga sd.Method = jwt.SigningMethodRS256 privateKeyData, err := ioutil.ReadFile(c.TokenSigning.PrivateKeyPath) if err != nil { - return nil, errors.Errorf("error reading token signing private key: %w", err) + return nil, errors.Wrapf(err, "error reading token signing private key") } sd.PrivateKey, err = jwt.ParseRSAPrivateKeyFromPEM(privateKeyData) if err != nil { - return nil, errors.Errorf("error parsing token signing private key: %w", err) + return nil, errors.Wrapf(err, "error parsing token signing private key") } publicKeyData, err := ioutil.ReadFile(c.TokenSigning.PublicKeyPath) if err != nil { - return nil, errors.Errorf("error reading token signing public key: %w", err) + return nil, errors.Wrapf(err, "error reading token signing public key") } sd.PublicKey, err = jwt.ParseRSAPublicKeyFromPEM(publicKeyData) if err != nil { - return nil, errors.Errorf("error parsing token signing public key: %w", err) + return nil, errors.Wrapf(err, "error parsing token signing public key") } case "": return nil, errors.Errorf("missing token signing method") @@ -115,7 +115,7 @@ func NewGateway(ctx context.Context, log zerolog.Logger, gc *config.Config) (*Ga ost, err := scommon.NewObjectStorage(&c.ObjectStorage) if err != nil { - return nil, err + return nil, errors.WithStack(err) } configstoreClient := csclient.NewClient(c.ConfigstoreURL) @@ -333,7 +333,7 @@ func (g *Gateway) Run(ctx context.Context) error { tlsConfig, err = util.NewTLSConfig(g.c.Web.TLSCertFile, g.c.Web.TLSKeyFile, "", false) if err != nil { g.log.Err(err).Send() - return err + return errors.WithStack(err) } } @@ -359,7 +359,7 @@ func (g *Gateway) Run(ctx context.Context) error { case err := <-lerrCh: if err != nil { log.Err(err).Msgf("http server listen error") - return err + return errors.WithStack(err) } } diff --git a/internal/services/gateway/handlers/auth.go b/internal/services/gateway/handlers/auth.go index 34ee2cc..06d5263 100644 --- a/internal/services/gateway/handlers/auth.go +++ b/internal/services/gateway/handlers/auth.go @@ -19,6 +19,7 @@ import ( "net/http" "strings" + "agola.io/agola/internal/errors" scommon "agola.io/agola/internal/services/common" "agola.io/agola/internal/services/gateway/common" "agola.io/agola/internal/util" @@ -27,7 +28,6 @@ import ( "github.com/golang-jwt/jwt/v4" jwtrequest "github.com/golang-jwt/jwt/v4/request" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) type AuthHandler struct { diff --git a/internal/services/gitserver/gitserver_test.go b/internal/services/gitserver/gitserver_test.go index 4859975..d9af295 100644 --- a/internal/services/gitserver/gitserver_test.go +++ b/internal/services/gitserver/gitserver_test.go @@ -16,13 +16,13 @@ package gitserver import ( "context" - "errors" "io/ioutil" "os" "path/filepath" "testing" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/config" "agola.io/agola/internal/testutil" "agola.io/agola/internal/util" diff --git a/internal/services/gitserver/main.go b/internal/services/gitserver/main.go index a902a74..1b0f500 100644 --- a/internal/services/gitserver/main.go +++ b/internal/services/gitserver/main.go @@ -23,6 +23,7 @@ import ( "regexp" "strings" + "agola.io/agola/internal/errors" handlers "agola.io/agola/internal/git-handler" "agola.io/agola/internal/services/config" "agola.io/agola/internal/util" @@ -30,7 +31,6 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - errors "golang.org/x/xerrors" ) const ( @@ -49,13 +49,13 @@ func repoPathIsValid(reposDir, repoPath string) (bool, error) { // check that a subdirectory doesn't exists reposDir, err := filepath.Abs(reposDir) if err != nil { - return false, err + return false, errors.WithStack(err) } path := repoPath _, err = os.Stat(path) if err != nil && !os.IsNotExist(err) { - return false, err + return false, errors.WithStack(err) } if !os.IsNotExist(err) { // if it exists assume it's valid @@ -70,7 +70,7 @@ func repoPathIsValid(reposDir, repoPath string) (bool, error) { _, err := os.Stat(path) if err != nil && !os.IsNotExist(err) { - return false, err + return false, errors.WithStack(err) } // a parent path cannot end with .git if strings.HasSuffix(path, gitSuffix) { @@ -88,7 +88,7 @@ func repoPathIsValid(reposDir, repoPath string) (bool, error) { func repoExists(repoAbsPath string) (bool, error) { _, err := os.Stat(repoAbsPath) if err != nil && !os.IsNotExist(err) { - return false, err + return false, errors.WithStack(err) } return !os.IsNotExist(err), nil } @@ -96,7 +96,7 @@ func repoExists(repoAbsPath string) (bool, error) { func repoAbsPath(reposDir, repoPath string) (string, bool, error) { valid, err := repoPathIsValid(reposDir, repoPath) if err != nil { - return "", false, err + return "", false, errors.WithStack(err) } if !valid { return "", false, handlers.ErrWrongRepoPath @@ -104,12 +104,12 @@ func repoAbsPath(reposDir, repoPath string) (string, bool, error) { repoFSPath, err := filepath.Abs(filepath.Join(reposDir, repoPath)) if err != nil { - return "", false, err + return "", false, errors.WithStack(err) } exists, err := repoExists(repoFSPath) if err != nil { - return "", false, err + return "", false, errors.WithStack(err) } return repoFSPath, exists, nil @@ -153,7 +153,7 @@ func (s *Gitserver) Run(ctx context.Context) error { tlsConfig, err = util.NewTLSConfig(s.c.Web.TLSCertFile, s.c.Web.TLSKeyFile, "", false) if err != nil { s.log.Err(err).Send() - return err + return errors.WithStack(err) } } @@ -182,7 +182,7 @@ func (s *Gitserver) Run(ctx context.Context) error { case err := <-lerrCh: if err != nil { s.log.Err(err).Msgf("http server listen error") - return err + return errors.WithStack(err) } } diff --git a/internal/services/gitserver/repo-cleaner.go b/internal/services/gitserver/repo-cleaner.go index 95bd0d8..cc7953c 100644 --- a/internal/services/gitserver/repo-cleaner.go +++ b/internal/services/gitserver/repo-cleaner.go @@ -2,13 +2,12 @@ package gitserver import ( "context" - "errors" - "fmt" "io/ioutil" "os" "path/filepath" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" ) @@ -32,7 +31,7 @@ func (s *Gitserver) scanRepos(ctx context.Context) error { usersDir, err := ioutil.ReadDir(s.c.DataDir) if err != nil { - return err + return errors.WithStack(err) } for _, u := range usersDir { @@ -64,12 +63,12 @@ func (s *Gitserver) scanRepo(ctx context.Context, repoDir string) error { for _, b := range branches { committerTime, err := s.getLastCommiterTime(ctx, git, "refs/heads/"+b) if err != nil { - return fmt.Errorf("return failed to get last commit time: %w", err) + return errors.Wrapf(err, "return failed to get last commit time") } if time.Since(committerTime) >= s.c.RepositoryRefsExpireInterval { if err := s.deleteBranch(ctx, git, b); err != nil { - return fmt.Errorf("failed to delete git branch: %w", err) + return errors.Wrapf(err, "failed to delete git branch") } } } @@ -78,34 +77,34 @@ func (s *Gitserver) scanRepo(ctx context.Context, repoDir string) error { for _, tag := range tags { committerTime, err := s.getLastCommiterTime(ctx, git, "refs/tags/"+tag) if err != nil { - return fmt.Errorf("failed to get last commit time: %w", err) + return errors.Wrapf(err, "failed to get last commit time") } if time.Since(committerTime) >= s.c.RepositoryRefsExpireInterval { if err := s.deleteTag(ctx, git, tag); err != nil { - return fmt.Errorf("failed to delete git tag: %w", err) + return errors.Wrapf(err, "failed to delete git tag") } } } if _, err := git.Output(ctx, nil, "prune"); err != nil { - return fmt.Errorf("git prune failed: %w", err) + return errors.Wrapf(err, "git prune failed") } b, err := s.getBranches(git, ctx) if err != nil { - return fmt.Errorf("failed to get git branches: %w", err) + return errors.Wrapf(err, "failed to get git branches") } t, err := s.getTags(git, ctx) if err != nil { - return fmt.Errorf("failed to get git tags: %w", err) + return errors.Wrapf(err, "failed to get git tags") } if len(b) == 0 && len(t) == 0 { s.log.Info().Msgf("deleting repo: %q", repoDir) if err := s.deleteRepo(ctx, repoDir); err != nil { - return fmt.Errorf("failed to delete repository: %w", err) + return errors.Wrapf(err, "failed to delete repository") } } @@ -115,7 +114,7 @@ func (s *Gitserver) scanRepo(ctx context.Context, repoDir string) error { func (s *Gitserver) getBranches(git *util.Git, ctx context.Context) ([]string, error) { branches, err := git.OutputLines(ctx, nil, "for-each-ref", "--format=%(refname:short)", "refs/heads/") if err != nil { - return nil, err + return nil, errors.WithStack(err) } return branches, nil @@ -124,7 +123,7 @@ func (s *Gitserver) getBranches(git *util.Git, ctx context.Context) ([]string, e func (s *Gitserver) getTags(git *util.Git, ctx context.Context) ([]string, error) { tags, err := git.OutputLines(ctx, nil, "for-each-ref", "--format=%(refname:short)", "refs/tags/") if err != nil { - return nil, err + return nil, errors.WithStack(err) } return tags, nil @@ -133,7 +132,7 @@ func (s *Gitserver) getTags(git *util.Git, ctx context.Context) ([]string, error func (s *Gitserver) getLastCommiterTime(ctx context.Context, git *util.Git, ref string) (time.Time, error) { output, err := git.OutputLines(ctx, nil, "log", "-1", "--format=%cI", ref) if err != nil { - return time.Time{}, err + return time.Time{}, errors.WithStack(err) } if len(output) != 1 { @@ -142,7 +141,7 @@ func (s *Gitserver) getLastCommiterTime(ctx context.Context, git *util.Git, ref committerTime, err := time.Parse(time.RFC3339, output[0]) if err != nil { - return time.Time{}, err + return time.Time{}, errors.WithStack(err) } return committerTime, nil @@ -150,14 +149,14 @@ func (s *Gitserver) getLastCommiterTime(ctx context.Context, git *util.Git, ref func (s *Gitserver) deleteBranch(ctx context.Context, git *util.Git, branch string) error { _, err := git.Output(ctx, nil, "branch", "-D", branch) - return err + return errors.WithStack(err) } func (s *Gitserver) deleteTag(ctx context.Context, git *util.Git, tag string) error { _, err := git.Output(ctx, nil, "tag", "-d", tag) - return err + return errors.WithStack(err) } func (s *Gitserver) deleteRepo(ctx context.Context, repoDir string) error { - return os.RemoveAll(repoDir) + return errors.WithStack(os.RemoveAll(repoDir)) } diff --git a/internal/services/notification/commitstatus.go b/internal/services/notification/commitstatus.go index b8a5e55..4466a07 100644 --- a/internal/services/notification/commitstatus.go +++ b/internal/services/notification/commitstatus.go @@ -19,12 +19,11 @@ import ( "fmt" "net/url" + "agola.io/agola/internal/errors" gitsource "agola.io/agola/internal/gitsources" "agola.io/agola/internal/services/common" "agola.io/agola/internal/services/gateway/action" rstypes "agola.io/agola/services/runservice/types" - - errors "golang.org/x/xerrors" ) func (n *NotificationService) updateCommitStatus(ctx context.Context, ev *rstypes.RunEvent) error { @@ -55,11 +54,11 @@ func (n *NotificationService) updateCommitStatus(ctx context.Context, ev *rstype run, _, err := n.runserviceClient.GetRun(ctx, ev.RunID, nil) if err != nil { - return err + return errors.WithStack(err) } groupType, groupID, err := common.GroupTypeIDFromRunGroup(run.RunConfig.Group) if err != nil { - return err + return errors.WithStack(err) } // ignore user direct runs @@ -69,12 +68,12 @@ func (n *NotificationService) updateCommitStatus(ctx context.Context, ev *rstype project, _, err := n.configstoreClient.GetProject(ctx, groupID) if err != nil { - return errors.Errorf("failed to get project %s: %w", groupID, err) + return errors.Wrapf(err, "failed to get project %s", groupID) } user, _, err := n.configstoreClient.GetUserByLinkedAccount(ctx, project.LinkedAccountID) if err != nil { - return errors.Errorf("failed to get user by linked account %q: %w", project.LinkedAccountID, err) + return errors.Wrapf(err, "failed to get user by linked account %q", project.LinkedAccountID) } la := user.LinkedAccounts[project.LinkedAccountID] if la == nil { @@ -82,24 +81,24 @@ func (n *NotificationService) updateCommitStatus(ctx context.Context, ev *rstype } rs, _, err := n.configstoreClient.GetRemoteSource(ctx, la.RemoteSourceID) if err != nil { - return errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, err) + return errors.Wrapf(err, "failed to get remote source %q", la.RemoteSourceID) } // TODO(sgotti) handle refreshing oauth2 tokens gitSource, err := common.GetGitSource(rs, la) if err != nil { - return errors.Errorf("failed to create gitea client: %w", err) + return errors.Wrapf(err, "failed to create gitea client") } targetURL, err := webRunURL(n.c.WebExposedURL, project.ID, run.Run.ID) if err != nil { - return errors.Errorf("failed to generate commit status target url: %w", err) + return errors.Wrapf(err, "failed to generate commit status target url") } description := statusDescription(commitStatus) context := fmt.Sprintf("%s/%s/%s", n.gc.ID, project.Name, run.RunConfig.Name) if err := gitSource.CreateCommitStatus(project.RepositoryPath, run.Run.Annotations[action.AnnotationCommitSHA], commitStatus, targetURL, description, context); err != nil { - return err + return errors.WithStack(err) } return nil @@ -108,7 +107,7 @@ func (n *NotificationService) updateCommitStatus(ctx context.Context, ev *rstype func webRunURL(webExposedURL, projectID, runID string) (string, error) { u, err := url.Parse(webExposedURL + "/run") if err != nil { - return "", err + return "", errors.WithStack(err) } q := url.Values{} q.Set("projectref", projectID) diff --git a/internal/services/notification/notification.go b/internal/services/notification/notification.go index 71bbc83..c03f41a 100644 --- a/internal/services/notification/notification.go +++ b/internal/services/notification/notification.go @@ -18,6 +18,8 @@ import ( "context" "agola.io/agola/internal/common" + "agola.io/agola/internal/errors" + "agola.io/agola/internal/etcd" "agola.io/agola/internal/services/config" csclient "agola.io/agola/services/configstore/client" @@ -46,7 +48,7 @@ func NewNotificationService(ctx context.Context, log zerolog.Logger, gc *config. e, err := common.NewEtcd(&c.Etcd, log, "notification") if err != nil { - return nil, err + return nil, errors.WithStack(err) } configstoreClient := csclient.NewClient(c.ConfigstoreURL) diff --git a/internal/services/notification/runevents.go b/internal/services/notification/runevents.go index 01a70fd..e6195e3 100644 --- a/internal/services/notification/runevents.go +++ b/internal/services/notification/runevents.go @@ -24,11 +24,11 @@ import ( "path" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" rstypes "agola.io/agola/services/runservice/types" "go.etcd.io/etcd/clientv3/concurrency" - errors "golang.org/x/xerrors" ) var ( @@ -53,7 +53,7 @@ func (n *NotificationService) runEventsHandlerLoop(ctx context.Context) { func (n *NotificationService) runEventsHandler(ctx context.Context) error { session, err := concurrency.NewSession(n.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -63,13 +63,13 @@ func (n *NotificationService) runEventsHandler(ctx context.Context) error { if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() resp, err := n.runserviceClient.GetRunEvents(ctx, "") if err != nil { - return err + return errors.WithStack(err) } if resp.StatusCode != http.StatusOK { return errors.Errorf("http status code: %d", resp.StatusCode) @@ -87,7 +87,7 @@ func (n *NotificationService) runEventsHandler(ctx context.Context) error { line, err := br.ReadBytes('\n') if err != nil { if err != io.EOF { - return err + return errors.WithStack(err) } if len(line) == 0 { return nil @@ -103,7 +103,7 @@ func (n *NotificationService) runEventsHandler(ctx context.Context) error { var ev *rstypes.RunEvent if err := json.Unmarshal(data, &ev); err != nil { - return err + return errors.WithStack(err) } // TODO(sgotti) diff --git a/internal/services/runservice/action/action.go b/internal/services/runservice/action/action.go index e526040..6d18482 100644 --- a/internal/services/runservice/action/action.go +++ b/internal/services/runservice/action/action.go @@ -16,12 +16,12 @@ package action import ( "context" - "fmt" "path" "time" "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/runconfig" @@ -33,7 +33,6 @@ import ( "agola.io/agola/services/runservice/types" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" ) type ActionHandler struct { @@ -69,12 +68,12 @@ type RunChangePhaseRequest struct { func (h *ActionHandler) ChangeRunPhase(ctx context.Context, req *RunChangePhaseRequest) error { cgt, err := types.UnmarshalChangeGroupsUpdateToken(req.ChangeGroupsUpdateToken) if err != nil { - return err + return errors.WithStack(err) } r, _, err := store.GetRun(ctx, h.e, req.RunID) if err != nil { - return err + return errors.WithStack(err) } var runEvent *types.RunEvent @@ -87,7 +86,7 @@ func (h *ActionHandler) ChangeRunPhase(ctx context.Context, req *RunChangePhaseR r.ChangePhase(types.RunPhaseRunning) runEvent, err = common.NewRunEvent(ctx, h.e, r.ID, r.Phase, r.Result) if err != nil { - return err + return errors.WithStack(err) } case types.RunPhaseCancelled: if r.Phase != types.RunPhaseQueued { @@ -96,7 +95,7 @@ func (h *ActionHandler) ChangeRunPhase(ctx context.Context, req *RunChangePhaseR r.ChangePhase(types.RunPhaseCancelled) runEvent, err = common.NewRunEvent(ctx, h.e, r.ID, r.Phase, r.Result) if err != nil { - return err + return errors.WithStack(err) } default: return errors.Errorf("unsupport change phase %q", req.Phase) @@ -104,7 +103,7 @@ func (h *ActionHandler) ChangeRunPhase(ctx context.Context, req *RunChangePhaseR } _, err = store.AtomicPutRun(ctx, h.e, r, runEvent, cgt) - return err + return errors.WithStack(err) } type RunStopRequest struct { @@ -115,12 +114,12 @@ type RunStopRequest struct { func (h *ActionHandler) StopRun(ctx context.Context, req *RunStopRequest) error { cgt, err := types.UnmarshalChangeGroupsUpdateToken(req.ChangeGroupsUpdateToken) if err != nil { - return err + return errors.WithStack(err) } r, _, err := store.GetRun(ctx, h.e, req.RunID) if err != nil { - return err + return errors.WithStack(err) } if r.Phase != types.RunPhaseRunning { @@ -132,7 +131,7 @@ func (h *ActionHandler) StopRun(ctx context.Context, req *RunStopRequest) error } _, err = store.AtomicPutRun(ctx, h.e, r, nil, cgt) - return err + return errors.WithStack(err) } type RunCreateRequest struct { @@ -158,7 +157,7 @@ type RunCreateRequest struct { func (h *ActionHandler) CreateRun(ctx context.Context, req *RunCreateRequest) (*types.RunBundle, error) { runcgt, err := types.UnmarshalChangeGroupsUpdateToken(req.ChangeGroupsUpdateToken) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var rb *types.RunBundle @@ -168,7 +167,7 @@ func (h *ActionHandler) CreateRun(ctx context.Context, req *RunCreateRequest) (* rb, err = h.recreateRun(ctx, req) } if err != nil { - return nil, err + return nil, errors.WithStack(err) } return rb, h.saveRun(ctx, rb, runcgt) @@ -191,7 +190,7 @@ func (h *ActionHandler) newRun(ctx context.Context, req *RunCreateRequest) (*typ // generate a new run sequence that will be the same for the run and runconfig seq, err := sequence.IncSequence(ctx, h.e, common.EtcdRunSequenceKey) if err != nil { - return nil, err + return nil, errors.WithStack(err) } id := seq.String() @@ -233,7 +232,7 @@ func (h *ActionHandler) recreateRun(ctx context.Context, req *RunCreateRequest) // generate a new run sequence that will be the same for the run and runconfig seq, err := sequence.IncSequence(ctx, h.e, common.EtcdRunSequenceKey) if err != nil { - return nil, err + return nil, errors.WithStack(err) } id := seq.String() @@ -241,15 +240,15 @@ func (h *ActionHandler) recreateRun(ctx context.Context, req *RunCreateRequest) h.log.Info().Msgf("creating run from existing run") rc, err := store.OSTGetRunConfig(h.dm, req.RunID) if err != nil { - return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("runconfig %q doesn't exist: %w", req.RunID, err)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "runconfig %q doesn't exist", req.RunID)) } run, err := store.GetRunEtcdOrOST(ctx, h.e, h.dm, req.RunID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if run == nil { - return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("run %q doesn't exist: %w", req.RunID, err)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Wrapf(err, "run %q doesn't exist", req.RunID)) } h.log.Debug().Msgf("rc: %s", util.Dump(rc)) @@ -300,7 +299,7 @@ func recreateRun(uuid util.UUIDGenerator, run *types.Run, rc *types.RunConfig, n if req.FromStart || rt.Status != types.RunTaskStatusSuccess { rct, ok := rc.Tasks[rt.ID] if !ok { - panic(fmt.Errorf("no runconfig task %q", rt.ID)) + panic(errors.Errorf("no runconfig task %q", rt.ID)) } // change rct id rct.ID = uuid.New(rct.Name).String() @@ -393,7 +392,7 @@ func (h *ActionHandler) saveRun(ctx context.Context, rb *types.RunBundle, runcgt c, cgt, err := h.getRunCounter(ctx, run.Group) h.log.Debug().Msgf("c: %d, cgt: %s", c, util.Dump(cgt)) if err != nil { - return err + return errors.WithStack(err) } c++ run.Counter = c @@ -405,27 +404,27 @@ func (h *ActionHandler) saveRun(ctx context.Context, rb *types.RunBundle, runcgt // persist group counter rca, err := store.OSTUpdateRunCounterAction(ctx, c, run.Group) if err != nil { - return err + return errors.WithStack(err) } actions = append(actions, rca) // persist run config rca, err = store.OSTSaveRunConfigAction(rc) if err != nil { - return err + return errors.WithStack(err) } actions = append(actions, rca) if _, err = h.dm.WriteWal(ctx, actions, cgt); err != nil { - return err + return errors.WithStack(err) } runEvent, err := common.NewRunEvent(ctx, h.e, run.ID, run.Phase, run.Result) if err != nil { - return err + return errors.WithStack(err) } if _, err := store.AtomicPutRun(ctx, h.e, run, runEvent, runcgt); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -500,12 +499,12 @@ type RunTaskSetAnnotationsRequest struct { func (h *ActionHandler) RunTaskSetAnnotations(ctx context.Context, req *RunTaskSetAnnotationsRequest) error { cgt, err := types.UnmarshalChangeGroupsUpdateToken(req.ChangeGroupsUpdateToken) if err != nil { - return err + return errors.WithStack(err) } r, _, err := store.GetRun(ctx, h.e, req.RunID) if err != nil { - return err + return errors.WithStack(err) } task, ok := r.Tasks[req.TaskID] @@ -516,7 +515,7 @@ func (h *ActionHandler) RunTaskSetAnnotations(ctx context.Context, req *RunTaskS task.Annotations = req.Annotations _, err = store.AtomicPutRun(ctx, h.e, r, nil, cgt) - return err + return errors.WithStack(err) } type RunTaskApproveRequest struct { @@ -528,12 +527,12 @@ type RunTaskApproveRequest struct { func (h *ActionHandler) ApproveRunTask(ctx context.Context, req *RunTaskApproveRequest) error { cgt, err := types.UnmarshalChangeGroupsUpdateToken(req.ChangeGroupsUpdateToken) if err != nil { - return err + return errors.WithStack(err) } r, _, err := store.GetRun(ctx, h.e, req.RunID) if err != nil { - return err + return errors.WithStack(err) } task, ok := r.Tasks[req.TaskID] @@ -553,12 +552,12 @@ func (h *ActionHandler) ApproveRunTask(ctx context.Context, req *RunTaskApproveR task.Approved = true _, err = store.AtomicPutRun(ctx, h.e, r, nil, cgt) - return err + return errors.WithStack(err) } func (h *ActionHandler) DeleteExecutor(ctx context.Context, executorID string) error { if err := store.DeleteExecutor(ctx, h.e, executorID); err != nil { - return err + return errors.WithStack(err) } return nil @@ -577,13 +576,13 @@ func (h *ActionHandler) getRunCounter(ctx context.Context, group string) (uint64 var err error c, err = h.readDB.GetRunCounterOST(tx, pl[1]) if err != nil { - return err + return errors.WithStack(err) } cgt, err = h.readDB.GetChangeGroupsUpdateTokensOST(tx, []string{"counter-" + pl[1]}) - return err + return errors.WithStack(err) }) if err != nil { - return 0, nil, err + return 0, nil, errors.WithStack(err) } return c, cgt, nil @@ -592,7 +591,7 @@ func (h *ActionHandler) getRunCounter(ctx context.Context, group string) (uint64 func (h *ActionHandler) GetExecutorTask(ctx context.Context, etID string) (*types.ExecutorTask, error) { et, err := store.GetExecutorTask(ctx, h.e, etID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return nil, err + return nil, errors.WithStack(err) } if et == nil { return nil, util.NewAPIError(util.ErrNotExist, errors.Errorf("executor task %q not found", etID)) @@ -600,11 +599,11 @@ func (h *ActionHandler) GetExecutorTask(ctx context.Context, etID string) (*type r, _, err := store.GetRun(ctx, h.e, et.Spec.RunID) if err != nil { - return nil, errors.Errorf("cannot get run %q: %w", et.Spec.RunID, err) + return nil, errors.Wrapf(err, "cannot get run %q", et.Spec.RunID) } rc, err := store.OSTGetRunConfig(h.dm, r.ID) if err != nil { - return nil, errors.Errorf("cannot get run config %q: %w", r.ID, err) + return nil, errors.Wrapf(err, "cannot get run config %q", r.ID) } rt, ok := r.Tasks[et.ID] if !ok { @@ -620,17 +619,17 @@ func (h *ActionHandler) GetExecutorTask(ctx context.Context, etID string) (*type func (h *ActionHandler) GetExecutorTasks(ctx context.Context, executorID string) ([]*types.ExecutorTask, error) { ets, err := store.GetExecutorTasksForExecutor(ctx, h.e, executorID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return nil, err + return nil, errors.WithStack(err) } for _, et := range ets { r, _, err := store.GetRun(ctx, h.e, et.Spec.RunID) if err != nil { - return nil, errors.Errorf("cannot get run %q: %w", et.Spec.RunID, err) + return nil, errors.Wrapf(err, "cannot get run %q", et.Spec.RunID) } rc, err := store.OSTGetRunConfig(h.dm, r.ID) if err != nil { - return nil, errors.Errorf("cannot get run config %q: %w", r.ID, err) + return nil, errors.Wrapf(err, "cannot get run config %q", r.ID) } rt, ok := r.Tasks[et.ID] if !ok { diff --git a/internal/services/runservice/action/maintenance.go b/internal/services/runservice/action/maintenance.go index 7705d73..176c23c 100644 --- a/internal/services/runservice/action/maintenance.go +++ b/internal/services/runservice/action/maintenance.go @@ -18,17 +18,16 @@ import ( "context" "io" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/services/runservice/common" "agola.io/agola/internal/util" - - errors "golang.org/x/xerrors" ) func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error { resp, err := h.e.Get(ctx, common.EtcdMaintenanceKey, 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if enable && len(resp.Kvs) > 0 { @@ -41,7 +40,7 @@ func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error if enable { txResp, err := h.e.AtomicPut(ctx, common.EtcdMaintenanceKey, []byte{}, 0, nil) if err != nil { - return err + return errors.WithStack(err) } if !txResp.Succeeded { return errors.Errorf("failed to create maintenance mode key due to concurrent update") @@ -51,7 +50,7 @@ func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error if !enable { txResp, err := h.e.AtomicDelete(ctx, common.EtcdMaintenanceKey, resp.Kvs[0].ModRevision) if err != nil { - return err + return errors.WithStack(err) } if !txResp.Succeeded { return errors.Errorf("failed to delete maintenance mode key due to concurrent update") @@ -62,12 +61,12 @@ func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error } func (h *ActionHandler) Export(ctx context.Context, w io.Writer) error { - return h.dm.Export(ctx, w) + return errors.WithStack(h.dm.Export(ctx, w)) } func (h *ActionHandler) Import(ctx context.Context, r io.Reader) error { if !h.maintenanceMode { return util.NewAPIError(util.ErrBadRequest, errors.Errorf("not in maintenance mode")) } - return h.dm.Import(ctx, r) + return errors.WithStack(h.dm.Import(ctx, r)) } diff --git a/internal/services/runservice/api/api.go b/internal/services/runservice/api/api.go index ffbae4f..f480ac7 100644 --- a/internal/services/runservice/api/api.go +++ b/internal/services/runservice/api/api.go @@ -24,6 +24,7 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/services/runservice/action" @@ -39,7 +40,6 @@ import ( etcdclientv3 "go.etcd.io/etcd/clientv3" etcdclientv3rpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" "go.etcd.io/etcd/mvcc/mvccpb" - errors "golang.org/x/xerrors" ) type ErrorResponse struct { @@ -104,12 +104,12 @@ func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { follow = true } - if err, sendError := h.readTaskLogs(ctx, runID, taskID, setup, step, w, follow); err != nil { + if sendError, err := h.readTaskLogs(ctx, runID, taskID, setup, step, w, follow); err != nil { h.log.Err(err).Send() if sendError { switch { case util.APIErrorIs(err, util.ErrNotExist): - util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("log doesn't exist: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Wrapf(err, "log doesn't exist"))) default: util.HTTPError(w, err) } @@ -117,21 +117,21 @@ func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } -func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, setup bool, step int, w http.ResponseWriter, follow bool) (error, bool) { +func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, setup bool, step int, w http.ResponseWriter, follow bool) (bool, error) { r, err := store.GetRunEtcdOrOST(ctx, h.e, h.dm, runID) if err != nil { - return err, true + return true, errors.WithStack(err) } if r == nil { - return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such run with id: %s", runID)), true + return true, util.NewAPIError(util.ErrNotExist, errors.Errorf("no such run with id: %s", runID)) } task, ok := r.Tasks[taskID] if !ok { - return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such task with ID %s in run %s", taskID, runID)), true + return true, util.NewAPIError(util.ErrNotExist, errors.Errorf("no such task with ID %s in run %s", taskID, runID)) } if len(task.Steps) <= step { - return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such step for task %s in run %s", taskID, runID)), true + return true, util.NewAPIError(util.ErrNotExist, errors.Errorf("no such step for task %s in run %s", taskID, runID)) } // if the log has been already fetched use it, otherwise fetch it from the executor @@ -145,27 +145,27 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se f, err := h.ost.ReadObject(logPath) if err != nil { if objectstorage.IsNotExist(err) { - return util.NewAPIError(util.ErrNotExist, err), true + return true, util.NewAPIError(util.ErrNotExist, err) } - return err, true + return true, errors.WithStack(err) } defer f.Close() - return sendLogs(w, f), false + return false, sendLogs(w, f) } et, err := store.GetExecutorTask(ctx, h.e, task.ID) if err != nil { if errors.Is(err, etcd.ErrKeyNotFound) { - return util.NewAPIError(util.ErrNotExist, errors.Errorf("executor task with id %q doesn't exist", task.ID)), true + return true, util.NewAPIError(util.ErrNotExist, errors.Errorf("executor task with id %q doesn't exist", task.ID)) } - return err, true + return true, errors.WithStack(err) } executor, err := store.GetExecutor(ctx, h.e, et.Spec.ExecutorID) if err != nil { if errors.Is(err, etcd.ErrKeyNotFound) { - return util.NewAPIError(util.ErrNotExist, errors.Errorf("executor with id %q doesn't exist", et.Spec.ExecutorID)), true + return true, util.NewAPIError(util.ErrNotExist, errors.Errorf("executor with id %q doesn't exist", et.Spec.ExecutorID)) } - return err, true + return true, errors.WithStack(err) } var url string @@ -179,14 +179,14 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se } req, err := http.Get(url) if err != nil { - return err, true + return true, errors.WithStack(err) } defer req.Body.Close() if req.StatusCode != http.StatusOK { if req.StatusCode == http.StatusNotFound { - return util.NewAPIError(util.ErrNotExist, errors.New("no log on executor")), true + return true, util.NewAPIError(util.ErrNotExist, errors.New("no log on executor")) } - return errors.Errorf("received http status: %d", req.StatusCode), true + return true, errors.Errorf("received http status: %d", req.StatusCode) } // write and flush the headers so the client will receive the response @@ -202,7 +202,7 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se flusher.Flush() } - return sendLogs(w, req.Body), false + return false, sendLogs(w, req.Body) } func sendLogs(w http.ResponseWriter, r io.Reader) error { @@ -221,7 +221,7 @@ func sendLogs(w http.ResponseWriter, r io.Reader) error { //data, err := br.ReadBytes('\n') if err != nil { if err != io.EOF { - return err + return errors.WithStack(err) } if n == 0 { return nil @@ -229,7 +229,7 @@ func sendLogs(w http.ResponseWriter, r io.Reader) error { stop = true } if _, err := w.Write(buf[:n]); err != nil { - return err + return errors.WithStack(err) } if flusher != nil { flusher.Flush() @@ -294,7 +294,7 @@ func (h *LogsDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.log.Err(err).Send() switch { case util.APIErrorIs(err, util.ErrNotExist): - util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("log doesn't exist: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Wrapf(err, "log doesn't exist"))) default: util.HTTPError(w, err) } @@ -304,7 +304,7 @@ func (h *LogsDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h *LogsDeleteHandler) deleteTaskLogs(ctx context.Context, runID, taskID string, setup bool, step int, w http.ResponseWriter) error { r, err := store.GetRunEtcdOrOST(ctx, h.e, h.dm, runID) if err != nil { - return err + return errors.WithStack(err) } if r == nil { return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such run with id: %s", runID)) @@ -330,7 +330,7 @@ func (h *LogsDeleteHandler) deleteTaskLogs(ctx context.Context, runID, taskID st if objectstorage.IsNotExist(err) { return util.NewAPIError(util.ErrNotExist, err) } - return err + return errors.WithStack(err) } return nil } @@ -359,7 +359,7 @@ func (h *ChangeGroupsUpdateTokensHandler) ServeHTTP(w http.ResponseWriter, r *ht err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, groups) - return err + return errors.WithStack(err) }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -409,11 +409,11 @@ func (h *RunHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { run, err = h.readDB.GetRun(tx, runID) if err != nil { h.log.Err(err).Send() - return err + return errors.WithStack(err) } cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, changeGroups) - return err + return errors.WithStack(err) }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -506,11 +506,11 @@ func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { runs, err = h.readDB.GetRuns(tx, groups, lastRun, phaseFilter, resultFilter, start, limit, sortOrder) if err != nil { h.log.Err(err).Send() - return err + return errors.WithStack(err) } cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, changeGroups) - return err + return errors.WithStack(err) }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -749,7 +749,7 @@ func (h *RunEventsHandler) sendRunEvents(ctx context.Context, startRunEventID st if errors.Is(err, etcdclientv3rpc.ErrCompacted) { h.log.Err(err).Msgf("required events already compacted") } - return errors.Errorf("watch error: %w", err) + return errors.Wrapf(err, "watch error") } for _, ev := range wresp.Events { @@ -757,10 +757,10 @@ func (h *RunEventsHandler) sendRunEvents(ctx context.Context, startRunEventID st case mvccpb.PUT: var runEvent *types.RunEvent if err := json.Unmarshal(ev.Kv.Value, &runEvent); err != nil { - return errors.Errorf("failed to unmarshal run: %w", err) + return errors.Wrapf(err, "failed to unmarshal run") } if _, err := w.Write([]byte(fmt.Sprintf("data: %s\n\n", ev.Kv.Value))); err != nil { - return err + return errors.WithStack(err) } } } diff --git a/internal/services/runservice/api/executor.go b/internal/services/runservice/api/executor.go index 41ac1e8..157b3ca 100644 --- a/internal/services/runservice/api/executor.go +++ b/internal/services/runservice/api/executor.go @@ -23,6 +23,7 @@ import ( "strconv" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/services/runservice/action" @@ -30,7 +31,6 @@ import ( "agola.io/agola/internal/services/runservice/store" "agola.io/agola/internal/util" "agola.io/agola/services/runservice/types" - errors "golang.org/x/xerrors" "github.com/gorilla/mux" "github.com/rs/zerolog" @@ -76,7 +76,7 @@ func (h *ExecutorStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request func (h *ExecutorStatusHandler) deleteStaleExecutors(ctx context.Context, curExecutor *types.Executor) error { executors, err := store.GetExecutors(ctx, h.e) if err != nil { - return err + return errors.WithStack(err) } for _, executor := range executors { @@ -251,14 +251,14 @@ func (h *ArchivesHandler) readArchive(rtID string, step int, w io.Writer) error if objectstorage.IsNotExist(err) { return util.NewAPIError(util.ErrNotExist, err) } - return err + return errors.WithStack(err) } defer f.Close() br := bufio.NewReader(f) _, err = io.Copy(w, br) - return err + return errors.WithStack(err) } type CacheHandler struct { @@ -328,7 +328,7 @@ func matchCache(ost *objectstorage.ObjStorage, key string, prefix bool) (string, var lastObject *objectstorage.ObjectInfo for object := range ost.List(store.OSTCacheDir()+"/"+key, "", false, doneCh) { if object.Err != nil { - return "", object.Err + return "", errors.WithStack(object.Err) } if (lastObject == nil) || (lastObject.LastModified.Before(object.LastModified)) { @@ -348,7 +348,7 @@ func matchCache(ost *objectstorage.ObjStorage, key string, prefix bool) (string, return "", nil } if err != nil { - return "", err + return "", errors.WithStack(err) } return key, nil } @@ -360,14 +360,14 @@ func (h *CacheHandler) readCache(key string, w io.Writer) error { if objectstorage.IsNotExist(err) { return util.NewAPIError(util.ErrNotExist, err) } - return err + return errors.WithStack(err) } defer f.Close() br := bufio.NewReader(f) _, err = io.Copy(w, br) - return err + return errors.WithStack(err) } type CacheCreateHandler struct { diff --git a/internal/services/runservice/common/common.go b/internal/services/runservice/common/common.go index 67f0f20..1111a96 100644 --- a/internal/services/runservice/common/common.go +++ b/internal/services/runservice/common/common.go @@ -15,10 +15,10 @@ package common import ( - "fmt" "path" "sort" + "agola.io/agola/internal/errors" "agola.io/agola/internal/runconfig" "agola.io/agola/internal/util" "agola.io/agola/services/runservice/types" @@ -84,7 +84,7 @@ const ( func OSTSubGroupsAndGroupTypes(group string) []string { h := util.PathHierarchy(group) if len(h)%2 != 1 { - panic(fmt.Errorf("wrong group path %q", group)) + panic(errors.Errorf("wrong group path %q", group)) } return h @@ -93,7 +93,7 @@ func OSTSubGroupsAndGroupTypes(group string) []string { func OSTRootGroup(group string) string { pl := util.PathList(group) if len(pl) < 2 { - panic(fmt.Errorf("cannot determine root group name, wrong group path %q", group)) + panic(errors.Errorf("cannot determine root group name, wrong group path %q", group)) } return pl[1] @@ -102,7 +102,7 @@ func OSTRootGroup(group string) string { func OSTSubGroups(group string) []string { h := util.PathHierarchy(group) if len(h)%2 != 1 { - panic(fmt.Errorf("wrong group path %q", group)) + panic(errors.Errorf("wrong group path %q", group)) } // remove group types @@ -119,7 +119,7 @@ func OSTSubGroups(group string) []string { func OSTSubGroupTypes(group string) []string { h := util.PathHierarchy(group) if len(h)%2 != 1 { - panic(fmt.Errorf("wrong group path %q", group)) + panic(errors.Errorf("wrong group path %q", group)) } // remove group names diff --git a/internal/services/runservice/common/events.go b/internal/services/runservice/common/events.go index 50a4fdf..e1fb447 100644 --- a/internal/services/runservice/common/events.go +++ b/internal/services/runservice/common/events.go @@ -17,6 +17,7 @@ package common import ( "context" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/sequence" "agola.io/agola/services/runservice/types" @@ -25,7 +26,7 @@ import ( func NewRunEvent(ctx context.Context, e *etcd.Store, runID string, phase types.RunPhase, result types.RunResult) (*types.RunEvent, error) { seq, err := sequence.IncSequence(ctx, e, EtcdRunEventSequenceKey) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return &types.RunEvent{Sequence: seq.String(), RunID: runID, Phase: phase, Result: result}, nil } diff --git a/internal/services/runservice/readdb/readdb.go b/internal/services/runservice/readdb/readdb.go index 2e13c38..4e12a6c 100644 --- a/internal/services/runservice/readdb/readdb.go +++ b/internal/services/runservice/readdb/readdb.go @@ -30,6 +30,7 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/db" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/sequence" @@ -43,7 +44,6 @@ import ( etcdclientv3 "go.etcd.io/etcd/clientv3" etcdclientv3rpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" "go.etcd.io/etcd/mvcc/mvccpb" - errors "golang.org/x/xerrors" ) const ( @@ -110,7 +110,7 @@ type ReadDB struct { func NewReadDB(ctx context.Context, log zerolog.Logger, dataDir string, e *etcd.Store, ost *objectstorage.ObjStorage, dm *datamanager.DataManager) (*ReadDB, error) { if err := os.MkdirAll(dataDir, 0770); err != nil { - return nil, err + return nil, errors.WithStack(err) } readDB := &ReadDB{ @@ -140,13 +140,13 @@ func (r *ReadDB) IsInitialized() bool { // revision to then feed it with the etcd events func (r *ReadDB) Initialize(ctx context.Context) error { if err := r.ResetDB(ctx); err != nil { - return errors.Errorf("failed to reset db: %w", err) + return errors.Wrapf(err, "failed to reset db") } if err := r.SyncObjectStorage(ctx); err != nil { - return errors.Errorf("error syncing objectstorage db: %w", err) + return errors.Wrapf(err, "error syncing objectstorage db") } if err := r.SyncRDB(ctx); err != nil { - return errors.Errorf("error syncing run db: %w", err) + return errors.Wrapf(err, "error syncing run db") } return nil } @@ -159,17 +159,17 @@ func (r *ReadDB) ResetDB(ctx context.Context) error { // drop rdb if err := os.Remove(filepath.Join(r.dataDir, "db")); err != nil { - return err + return errors.WithStack(err) } rdb, err := db.NewDB(db.Sqlite3, filepath.Join(r.dataDir, "db")) if err != nil { - return err + return errors.WithStack(err) } // populate readdb if err := rdb.Create(ctx, Stmts); err != nil { - return err + return errors.WithStack(err) } r.rdb = rdb @@ -187,7 +187,7 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { for { listResp, err := r.e.ListPaged(ctx, key, revision, paginationSize, continuation) if err != nil { - return err + return errors.WithStack(err) } resp := listResp.Resp continuation = listResp.Continuation @@ -199,11 +199,11 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { for _, kv := range resp.Kvs { var run *types.Run if err := json.Unmarshal(kv.Value, &run); err != nil { - return err + return errors.WithStack(err) } if err := insertRun(tx, run, kv.Value); err != nil { - return err + return errors.WithStack(err) } } @@ -218,7 +218,7 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { for { listResp, err := r.e.ListPaged(ctx, key, revision, paginationSize, continuation) if err != nil { - return err + return errors.WithStack(err) } resp := listResp.Resp continuation = listResp.Continuation @@ -227,7 +227,7 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { changegroupID := path.Base(string(kv.Key)) if err := insertChangeGroupRevision(tx, changegroupID, kv.ModRevision); err != nil { - return err + return errors.WithStack(err) } } @@ -237,13 +237,13 @@ func (r *ReadDB) SyncRDB(ctx context.Context) error { } if err := insertRevision(tx, revision); err != nil { - return err + return errors.WithStack(err) } return nil }) - return err + return errors.WithStack(err) } func (r *ReadDB) Run(ctx context.Context) error { @@ -252,19 +252,19 @@ func (r *ReadDB) Run(ctx context.Context) error { } rdb, err := db.NewDB(db.Sqlite3, filepath.Join(r.dataDir, "db")) if err != nil { - return err + return errors.WithStack(err) } r.rdb = rdb // populate readdb if err := r.rdb.Create(ctx, Stmts); err != nil { - return err + return errors.WithStack(err) } revision, err := r.GetRevision(ctx) if err != nil { - return err + return errors.WithStack(err) } if revision == 0 { @@ -357,18 +357,18 @@ func (r *ReadDB) handleEvents(ctx context.Context) error { var err error revision, err = r.getRevision(tx) if err != nil { - return err + return errors.WithStack(err) } lastRuns, err = r.GetActiveRuns(tx, nil, true, nil, nil, "", 1, types.SortOrderDesc) - return err + return errors.WithStack(err) }) if err != nil { - return err + return errors.WithStack(err) } runSequence, _, err := sequence.CurSequence(ctx, r.e, common.EtcdRunSequenceKey) if err != nil { - return err + return errors.WithStack(err) } var lastRun *types.Run @@ -383,7 +383,7 @@ func (r *ReadDB) handleEvents(ctx context.Context) error { lastRunSequence, err := sequence.Parse(lastRun.ID) if err != nil { - return err + return errors.WithStack(err) } // check that the run sequence epoch isn't different than the current one (this means etcd // has been reset, or worst, restored from a backup or manually deleted) @@ -404,7 +404,7 @@ func (r *ReadDB) handleEvents(ctx context.Context) error { r.log.Err(err).Msgf("required events already compacted, reinitializing readdb") r.SetInitialized(false) } - return errors.Errorf("watch error: %w", err) + return errors.Wrapf(err, "watch error") } // a single transaction for every response (every response contains all the @@ -413,18 +413,18 @@ func (r *ReadDB) handleEvents(ctx context.Context) error { err = r.rdb.Do(ctx, func(tx *db.Tx) error { for _, ev := range wresp.Events { if err := r.handleEvent(tx, ev, &wresp); err != nil { - return err + return errors.WithStack(err) } if err := insertRevision(tx, ev.Kv.ModRevision); err != nil { - return err + return errors.WithStack(err) } } return nil }) r.dbWriteLock.Unlock() if err != nil { - return err + return errors.WithStack(err) } } @@ -454,7 +454,7 @@ func (r *ReadDB) handleRunEvent(tx *db.Tx, ev *etcdclientv3.Event, wresp *etcdcl case mvccpb.PUT: var run *types.Run if err := json.Unmarshal(ev.Kv.Value, &run); err != nil { - return errors.Errorf("failed to unmarshal run: %w", err) + return errors.Wrapf(err, "failed to unmarshal run") } return insertRun(tx, run, ev.Kv.Value) @@ -463,7 +463,7 @@ func (r *ReadDB) handleRunEvent(tx *db.Tx, ev *etcdclientv3.Event, wresp *etcdcl runID := path.Base(string(ev.Kv.Key)) if _, err := tx.Exec("delete from run where id = $1", runID); err != nil { - return errors.Errorf("failed to delete run: %w", err) + return errors.Wrapf(err, "failed to delete run") } // Run has been deleted from etcd, this means that it was stored in the objectstorage @@ -472,7 +472,7 @@ func (r *ReadDB) handleRunEvent(tx *db.Tx, ev *etcdclientv3.Event, wresp *etcdcl // implement run removal run, err := store.OSTGetRun(r.dm, runID) if err != nil { - return err + return errors.WithStack(err) } return r.insertRunOST(tx, run, []byte{}) @@ -486,18 +486,18 @@ func (r *ReadDB) handleRunsEventEvent(tx *db.Tx, ev *etcdclientv3.Event, wresp * case mvccpb.PUT: var runEvent *types.RunEvent if err := json.Unmarshal(ev.Kv.Value, &runEvent); err != nil { - return errors.Errorf("failed to unmarshal run: %w", err) + return errors.Wrapf(err, "failed to unmarshal run") } // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from runevent where sequence = $1", runEvent.Sequence); err != nil { - return errors.Errorf("failed to delete run: %w", err) + return errors.Wrapf(err, "failed to delete run") } q, args, err := runeventInsert.Values(runEvent.Sequence, ev.Kv.Value).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } } @@ -513,7 +513,7 @@ func (r *ReadDB) handleChangeGroupEvent(tx *db.Tx, ev *etcdclientv3.Event, wresp case mvccpb.DELETE: if _, err := tx.Exec("delete from changegrouprevision where id = $1", changegroupID); err != nil { - return errors.Errorf("failed to delete change group revision: %w", err) + return errors.Wrapf(err, "failed to delete change group revision") } } @@ -527,17 +527,17 @@ func (r *ReadDB) SyncObjectStorage(ctx context.Context) error { var err error curWalSeq, err = r.GetCommittedWalSequenceOST(tx) if err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return err + return errors.WithStack(err) } lastCommittedStorageWal, _, err := r.dm.LastCommittedStorageWal(ctx) if err != nil { - return err + return errors.WithStack(err) } doFullSync := false @@ -547,7 +547,7 @@ func (r *ReadDB) SyncObjectStorage(ctx context.Context) error { } else { ok, err := r.dm.HasOSTWal(curWalSeq) if err != nil { - return err + return errors.WithStack(err) } if !ok { r.log.Warn().Msgf("no wal with seq %q in objectstorage, doing a full sync", curWalSeq) @@ -561,13 +561,13 @@ func (r *ReadDB) SyncObjectStorage(ctx context.Context) error { // TODO(sgotti) improve this to avoid doing a full resync curWalSequence, err := sequence.Parse(curWalSeq) if err != nil { - return err + return errors.WithStack(err) } curWalEpoch := curWalSequence.Epoch lastCommittedStorageWalSequence, err := sequence.Parse(lastCommittedStorageWal) if err != nil { - return err + return errors.WithStack(err) } if curWalEpoch != lastCommittedStorageWalSequence.Epoch { r.log.Warn().Msgf("current rdb wal sequence epoch %d different than new wal sequence epoch %d, doing a full sync", curWalEpoch, lastCommittedStorageWalSequence.Epoch) @@ -578,13 +578,13 @@ func (r *ReadDB) SyncObjectStorage(ctx context.Context) error { if doFullSync { r.log.Info().Msgf("doing a full sync from dump") if err := r.ResetDB(ctx); err != nil { - return err + return errors.WithStack(err) } var err error curWalSeq, err = r.SyncFromDump(ctx) if err != nil { - return err + return errors.WithStack(err) } } @@ -597,7 +597,7 @@ func (r *ReadDB) SyncObjectStorage(ctx context.Context) error { // in etcd curWalSeq, err = r.SyncFromWals(ctx, curWalSeq, lastCommittedStorageWal) if err != nil { - return errors.Errorf("failed to sync from wals: %w", err) + return errors.Wrapf(err, "failed to sync from wals") } // Get the first available wal from etcd and check that our current walseq @@ -606,7 +606,7 @@ func (r *ReadDB) SyncObjectStorage(ctx context.Context) error { // many new wals are written, the next sync should be faster and able to continue firstAvailableWalData, revision, err := r.dm.FirstAvailableWalData(ctx) if err != nil { - return errors.Errorf("failed to get first available wal data: %w", err) + return errors.Wrapf(err, "failed to get first available wal data") } r.log.Debug().Msgf("firstAvailableWalData: %s", util.Dump(firstAvailableWalData)) r.log.Debug().Msgf("revision: %d", revision) @@ -620,13 +620,13 @@ func (r *ReadDB) SyncObjectStorage(ctx context.Context) error { r.log.Info().Msgf("syncing from wals") err = r.rdb.Do(ctx, func(tx *db.Tx) error { if err := insertRevisionOST(tx, revision); err != nil { - return err + return errors.WithStack(err) } // use the same revision as previous operation for walElement := range r.dm.ListEtcdWals(ctx, revision) { if walElement.Err != nil { - return walElement.Err + return errors.WithStack(walElement.Err) } if walElement.WalData.WalSequence <= curWalSeq { continue @@ -638,43 +638,43 @@ func (r *ReadDB) SyncObjectStorage(ctx context.Context) error { } if err := r.insertCommittedWalSequenceOST(tx, walElement.WalData.WalSequence); err != nil { - return err + return errors.WithStack(err) } r.log.Debug().Msgf("applying wal to db") if err := r.applyWal(tx, walElement.WalData.WalDataFileID); err != nil { - return err + return errors.WithStack(err) } } // sync changegroups, use the same revision of previous operations changeGroupsRevisions, err := r.dm.ListEtcdChangeGroups(ctx, revision) if err != nil { - return err + return errors.WithStack(err) } for changeGroupID, changeGroupRevision := range changeGroupsRevisions { if err := r.insertChangeGroupRevisionOST(tx, changeGroupID, changeGroupRevision); err != nil { - return err + return errors.WithStack(err) } } return nil }) - return err + return errors.WithStack(err) } func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) { dumpIndex, err := r.dm.GetLastDataStatus() if err != nil { - return "", err + return "", errors.WithStack(err) } for dataType, files := range dumpIndex.Files { for _, file := range files { dumpf, err := r.ost.ReadObject(r.dm.DataFilePath(dataType, file.ID)) if err != nil { - return "", err + return "", errors.WithStack(err) } dumpEntries := []*datamanager.DataEntry{} dec := json.NewDecoder(dumpf) @@ -688,7 +688,7 @@ func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) { } if err != nil { dumpf.Close() - return "", err + return "", errors.WithStack(err) } dumpEntries = append(dumpEntries, de) } @@ -703,25 +703,25 @@ func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) { Data: de.Data, } if err := r.applyAction(tx, action); err != nil { - return err + return errors.WithStack(err) } } return nil }) if err != nil { - return "", err + return "", errors.WithStack(err) } } } err = r.rdb.Do(ctx, func(tx *db.Tx) error { if err := r.insertCommittedWalSequenceOST(tx, dumpIndex.WalSequence); err != nil { - return err + return errors.WithStack(err) } return nil }) if err != nil { - return "", err + return "", errors.WithStack(err) } return dumpIndex.WalSequence, nil @@ -733,18 +733,18 @@ func (r *ReadDB) SyncFromWals(ctx context.Context, startWalSeq, endWalSeq string for _, walFile := range walFiles { header, err := r.dm.ReadWal(walFile.WalSequence) if err != nil { - return err + return errors.WithStack(err) } if err := r.insertCommittedWalSequenceOST(tx, walFile.WalSequence); err != nil { - return err + return errors.WithStack(err) } if err := r.applyWal(tx, header.WalDataFileID); err != nil { - return err + return errors.WithStack(err) } } return nil }) - return err + return errors.WithStack(err) } lastWalSeq := startWalSeq @@ -756,7 +756,7 @@ func (r *ReadDB) SyncFromWals(ctx context.Context, startWalSeq, endWalSeq string for walFile := range r.dm.ListOSTWals(startWalSeq) { if walFile.Err != nil { - return "", walFile.Err + return "", errors.WithStack(walFile.Err) } walFiles = append(walFiles, walFile) @@ -764,7 +764,7 @@ func (r *ReadDB) SyncFromWals(ctx context.Context, startWalSeq, endWalSeq string if count > 100 { if err := insertfunc(walFiles); err != nil { - return "", err + return "", errors.WithStack(err) } count = 0 walFiles = []*datamanager.WalFile{} @@ -773,7 +773,7 @@ func (r *ReadDB) SyncFromWals(ctx context.Context, startWalSeq, endWalSeq string } } if err := insertfunc(walFiles); err != nil { - return "", err + return "", errors.WithStack(err) } return lastWalSeq, nil @@ -787,13 +787,13 @@ func (r *ReadDB) handleEventsOST(ctx context.Context) error { if errors.Is(err, sql.ErrNoRows) { revision = 0 } else { - return err + return errors.WithStack(err) } } return nil }) if err != nil { - return err + return errors.WithStack(err) } wctx, cancel := context.WithCancel(ctx) @@ -809,7 +809,7 @@ func (r *ReadDB) handleEventsOST(ctx context.Context) error { r.Initialized = false return nil } - return errors.Errorf("watch error: %w", err) + return errors.Wrapf(err, "watch error") } // a single transaction for every response (every response contains all the @@ -824,19 +824,19 @@ func (r *ReadDB) handleEventsOST(ctx context.Context) error { // lost from etcd) curWalSeq, err := r.GetCommittedWalSequenceOST(tx) if err != nil { - return err + return errors.WithStack(err) } r.log.Debug().Msgf("curWalSeq: %q", curWalSeq) if curWalSeq != "" && we.WalData != nil { curWalSequence, err := sequence.Parse(curWalSeq) if err != nil { - return err + return errors.WithStack(err) } curWalEpoch := curWalSequence.Epoch weWalSequence, err := sequence.Parse(we.WalData.WalSequence) if err != nil { - return err + return errors.WithStack(err) } r.log.Debug().Msgf("we.WalData.WalSequence: %q", we.WalData.WalSequence) weWalEpoch := weWalSequence.Epoch @@ -847,17 +847,17 @@ func (r *ReadDB) handleEventsOST(ctx context.Context) error { } if err := r.handleEventOST(tx, we); err != nil { - return err + return errors.WithStack(err) } if err := insertRevisionOST(tx, we.Revision); err != nil { - return err + return errors.WithStack(err) } return nil }) r.dbWriteLock.Unlock() if err != nil { - return err + return errors.WithStack(err) } } @@ -867,7 +867,7 @@ func (r *ReadDB) handleEventsOST(ctx context.Context) error { func (r *ReadDB) applyWal(tx *db.Tx, walDataFileID string) error { walFile, err := r.dm.ReadWalData(walDataFileID) if err != nil { - return errors.Errorf("cannot read wal data file %q: %w", walDataFileID, err) + return errors.Wrapf(err, "cannot read wal data file %q", walDataFileID) } defer walFile.Close() @@ -881,11 +881,11 @@ func (r *ReadDB) applyWal(tx *db.Tx, walDataFileID string) error { break } if err != nil { - return errors.Errorf("failed to decode wal file: %w", err) + return errors.Wrapf(err, "failed to decode wal file") } if err := r.applyAction(tx, action); err != nil { - return err + return errors.WithStack(err) } } @@ -900,19 +900,19 @@ func (r *ReadDB) applyAction(tx *db.Tx, action *datamanager.Action) error { case string(common.DataTypeRun): var run *types.Run if err := json.Unmarshal(action.Data, &run); err != nil { - return err + return errors.WithStack(err) } if err := r.insertRunOST(tx, run, action.Data); err != nil { - return err + return errors.WithStack(err) } case string(common.DataTypeRunCounter): var runCounter uint64 if err := json.Unmarshal(action.Data, &runCounter); err != nil { - return err + return errors.WithStack(err) } r.log.Debug().Msgf("inserting run counter %q, c: %d", action.ID, runCounter) if err := r.insertRunCounterOST(tx, action.ID, runCounter); err != nil { - return err + return errors.WithStack(err) } } @@ -931,7 +931,7 @@ func (r *ReadDB) handleEventOST(tx *db.Tx, we *datamanager.WatchElement) error { //key := string(ev.Kv.Key) if err := r.handleWalEvent(tx, we); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -939,7 +939,7 @@ func (r *ReadDB) handleEventOST(tx *db.Tx, we *datamanager.WatchElement) error { func (r *ReadDB) handleWalEvent(tx *db.Tx, we *datamanager.WatchElement) error { for cgName, cgRev := range we.ChangeGroupsRevisions { if err := r.insertChangeGroupRevisionOST(tx, cgName, cgRev); err != nil { - return err + return errors.WithStack(err) } } @@ -950,7 +950,7 @@ func (r *ReadDB) handleWalEvent(tx *db.Tx, we *datamanager.WatchElement) error { } if err := r.insertCommittedWalSequenceOST(tx, we.WalData.WalSequence); err != nil { - return err + return errors.WithStack(err) } r.log.Debug().Msgf("applying wal to db") @@ -963,22 +963,22 @@ func (r *ReadDB) Do(ctx context.Context, f func(tx *db.Tx) error) error { if !r.IsInitialized() { return errors.Errorf("db not initialized") } - return r.rdb.Do(ctx, f) + return errors.WithStack(r.rdb.Do(ctx, f)) } func insertRevision(tx *db.Tx, revision int64) error { // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from revision"); err != nil { - return errors.Errorf("failed to delete revision: %w", err) + return errors.Wrapf(err, "failed to delete revision") } // TODO(sgotti) go database/sql and mattn/sqlite3 don't support uint64 types... //q, args, err = revisionInsert.Values(int64(wresp.Header.ClusterId), run.Revision).ToSql() q, args, err := revisionInsert.Values(revision).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -986,16 +986,16 @@ func insertRevision(tx *db.Tx, revision int64) error { func insertRevisionOST(tx *db.Tx, revision int64) error { // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from revision_ost"); err != nil { - return errors.Errorf("failed to delete revision: %w", err) + return errors.Wrapf(err, "failed to delete revision") } // TODO(sgotti) go database/sql and mattn/sqlite3 don't support uint64 types... //q, args, err = revisionInsert.Values(int64(wresp.Header.ClusterId), run.Revision).ToSql() q, args, err := revisionOSTInsert.Values(revision).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -1009,26 +1009,26 @@ func insertRun(tx *db.Tx, run *types.Run, data []byte) error { // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from run where id = $1", run.ID); err != nil { - return errors.Errorf("failed to delete run: %w", err) + return errors.Wrapf(err, "failed to delete run") } q, args, err := runInsert.Values(run.ID, groupPath, run.Phase, run.Result).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from rundata where id = $1", run.ID); err != nil { - return errors.Errorf("failed to delete rundata: %w", err) + return errors.Wrapf(err, "failed to delete rundata") } q, args, err = rundataInsert.Values(run.ID, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } return nil @@ -1043,26 +1043,26 @@ func (r *ReadDB) insertRunOST(tx *db.Tx, run *types.Run, data []byte) error { // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from run_ost where id = $1", run.ID); err != nil { - return errors.Errorf("failed to delete run objectstorage: %w", err) + return errors.Wrapf(err, "failed to delete run objectstorage") } q, args, err := runOSTInsert.Values(run.ID, groupPath, run.Phase, run.Result).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from rundata_ost where id = $1", run.ID); err != nil { - return errors.Errorf("failed to delete rundata: %w", err) + return errors.Wrapf(err, "failed to delete rundata") } q, args, err = rundataOSTInsert.Values(run.ID, data).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } return nil @@ -1071,14 +1071,14 @@ func (r *ReadDB) insertRunOST(tx *db.Tx, run *types.Run, data []byte) error { func insertChangeGroupRevision(tx *db.Tx, changegroupID string, revision int64) error { // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from changegrouprevision where id = $1", changegroupID); err != nil { - return errors.Errorf("failed to delete run: %w", err) + return errors.Wrapf(err, "failed to delete run") } q, args, err := changegrouprevisionInsert.Values(changegroupID, revision).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -1089,9 +1089,9 @@ func (r *ReadDB) GetRevision(ctx context.Context) (int64, error) { err := r.rdb.Do(ctx, func(tx *db.Tx) error { var err error revision, err = r.getRevision(tx) - return err + return errors.WithStack(err) }) - return revision, err + return revision, errors.WithStack(err) } func (r *ReadDB) getRevision(tx *db.Tx) (int64, error) { @@ -1100,14 +1100,14 @@ func (r *ReadDB) getRevision(tx *db.Tx) (int64, error) { q, args, err := revisionSelect.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return 0, errors.Errorf("failed to build query: %w", err) + return 0, errors.Wrapf(err, "failed to build query") } err = tx.QueryRow(q, args...).Scan(&revision) if errors.Is(err, sql.ErrNoRows) { return 0, nil } - return revision, err + return revision, errors.WithStack(err) } func (r *ReadDB) GetChangeGroupsUpdateTokens(tx *db.Tx, groups []string) (*types.ChangeGroupsUpdateToken, error) { @@ -1115,16 +1115,16 @@ func (r *ReadDB) GetChangeGroupsUpdateTokens(tx *db.Tx, groups []string) (*types q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } changeGroupsRevisions, err := fetchChangeGroupsRevision(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } revision, err := r.getRevision(tx) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // for non existing changegroups use a changegroup with revision = 0 @@ -1154,7 +1154,7 @@ func (r *ReadDB) GetRuns(tx *db.Tx, groups []string, lastRun bool, phaseFilter [ runDataRDB, err := r.getRunsFilteredActive(tx, groups, lastRun, phaseFilter, resultFilter, startRunID, limit, sortOrder) if err != nil { - return nil, err + return nil, errors.WithStack(err) } lastRunsMap := map[string]*RunData{} runsMap := map[string]*RunData{} @@ -1167,7 +1167,7 @@ func (r *ReadDB) GetRuns(tx *db.Tx, groups []string, lastRun bool, phaseFilter [ // skip if the phase requested is not finished runDataOST, err := r.GetRunsFilteredOST(tx, groups, lastRun, phaseFilter, resultFilter, startRunID, limit, sortOrder) if err != nil { - return nil, err + return nil, errors.WithStack(err) } for _, rd := range runDataOST { @@ -1222,7 +1222,7 @@ func (r *ReadDB) GetRuns(tx *db.Tx, groups []string, lastRun bool, phaseFilter [ // get run from objectstorage run, err := store.OSTGetRun(r.dm, runID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } aruns = append(aruns, run) @@ -1304,7 +1304,7 @@ func (r *ReadDB) getRunsFilteredActive(tx *db.Tx, groups []string, lastRun bool, q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } return fetchRuns(tx, q, args...) @@ -1316,7 +1316,7 @@ func (r *ReadDB) GetRunsFilteredOST(tx *db.Tx, groups []string, lastRun bool, ph q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } return fetchRuns(tx, q, args...) @@ -1325,7 +1325,7 @@ func (r *ReadDB) GetRunsFilteredOST(tx *db.Tx, groups []string, lastRun bool, ph func (r *ReadDB) GetRun(tx *db.Tx, runID string) (*types.Run, error) { run, err := r.getRun(tx, runID, false) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if run != nil { return run, nil @@ -1341,12 +1341,12 @@ func (r *ReadDB) getRun(tx *db.Tx, runID string, ost bool) (*types.Run, error) { q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } runsData, err := fetchRuns(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if len(runsData) > 1 { return nil, errors.Errorf("too many rows returned") @@ -1364,7 +1364,7 @@ func (r *ReadDB) getRun(tx *db.Tx, runID string, ost bool) (*types.Run, error) { // get run from objectstorage run, err = store.OSTGetRun(r.dm, runID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } } @@ -1396,7 +1396,7 @@ type RunData struct { func fetchRuns(tx *db.Tx, q string, args ...interface{}) ([]*RunData, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer rows.Close() return scanRuns(rows) @@ -1406,11 +1406,11 @@ func scanRun(rows *sql.Rows) (*RunData, error) { r := &RunData{} var data []byte if err := rows.Scan(&r.ID, &r.GroupPath, &r.Phase, &data); err != nil { - return nil, errors.Errorf("failed to scan rows: %w", err) + return nil, errors.Wrapf(err, "failed to scan rows") } if len(data) > 0 { if err := json.Unmarshal(data, &r.Run); err != nil { - return nil, errors.Errorf("failed to unmarshal run: %w", err) + return nil, errors.Wrapf(err, "failed to unmarshal run") } } @@ -1422,12 +1422,12 @@ func scanRuns(rows *sql.Rows) ([]*RunData, error) { for rows.Next() { r, err := scanRun(rows) if err != nil { - return nil, err + return nil, errors.WithStack(err) } runs = append(runs, r) } if err := rows.Err(); err != nil { - return nil, err + return nil, errors.WithStack(err) } return runs, nil } @@ -1435,7 +1435,7 @@ func scanRuns(rows *sql.Rows) ([]*RunData, error) { func fetchChangeGroupsRevision(tx *db.Tx, q string, args ...interface{}) (types.ChangeGroupsRevisions, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer rows.Close() return scanChangeGroupsRevision(rows) @@ -1449,12 +1449,12 @@ func scanChangeGroupsRevision(rows *sql.Rows) (types.ChangeGroupsRevisions, erro revision int64 ) if err := rows.Scan(&id, &revision); err != nil { - return nil, errors.Errorf("failed to scan rows: %w", err) + return nil, errors.Wrapf(err, "failed to scan rows") } changegroups[id] = revision } if err := rows.Err(); err != nil { - return nil, err + return nil, errors.WithStack(err) } return changegroups, nil } @@ -1463,14 +1463,14 @@ func (r *ReadDB) insertCommittedWalSequenceOST(tx *db.Tx, seq string) error { r.log.Debug().Msgf("insert seq: %s", seq) // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from committedwalsequence_ost"); err != nil { - return errors.Errorf("failed to delete committedwalsequence: %w", err) + return errors.Wrapf(err, "failed to delete committedwalsequence") } q, args, err := committedwalsequenceOSTInsert.Values(seq).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -1481,14 +1481,14 @@ func (r *ReadDB) GetCommittedWalSequenceOST(tx *db.Tx) (string, error) { q, args, err := committedwalsequenceOSTSelect.OrderBy("seq").Limit(1).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return "", errors.Errorf("failed to build query: %w", err) + return "", errors.Wrapf(err, "failed to build query") } err = tx.QueryRow(q, args...).Scan(&seq) if errors.Is(err, sql.ErrNoRows) { return "", nil } - return seq, err + return seq, errors.WithStack(err) } func (r *ReadDB) insertChangeGroupRevisionOST(tx *db.Tx, changegroup string, revision int64) error { @@ -1496,16 +1496,16 @@ func (r *ReadDB) insertChangeGroupRevisionOST(tx *db.Tx, changegroup string, rev // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from changegrouprevision_ost where id = $1", changegroup); err != nil { - return errors.Errorf("failed to delete run: %w", err) + return errors.Wrapf(err, "failed to delete run") } // insert only if revision > 0 if revision > 0 { q, args, err := changegrouprevisionOSTInsert.Values(changegroup, revision).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } } return nil @@ -1516,16 +1516,16 @@ func (r *ReadDB) GetChangeGroupsUpdateTokensOST(tx *db.Tx, groups []string) (*da q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } cgr, err := fetchChangeGroupsRevisionOST(tx, q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } revision, err := r.getRevision(tx) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // for non existing changegroups use a changegroup with revision = 0 @@ -1541,7 +1541,7 @@ func (r *ReadDB) GetChangeGroupsUpdateTokensOST(tx *db.Tx, groups []string) (*da func fetchChangeGroupsRevisionOST(tx *db.Tx, q string, args ...interface{}) (map[string]int64, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer rows.Close() return scanChangeGroupsRevisionOST(rows) @@ -1555,12 +1555,12 @@ func scanChangeGroupsRevisionOST(rows *sql.Rows) (map[string]int64, error) { revision int64 ) if err := rows.Scan(&id, &revision); err != nil { - return nil, errors.Errorf("failed to scan rows: %w", err) + return nil, errors.Wrapf(err, "failed to scan rows") } changegroups[id] = revision } if err := rows.Err(); err != nil { - return nil, err + return nil, errors.WithStack(err) } return changegroups, nil } @@ -1568,16 +1568,16 @@ func scanChangeGroupsRevisionOST(rows *sql.Rows) (map[string]int64, error) { func (r *ReadDB) insertRunCounterOST(tx *db.Tx, group string, counter uint64) error { // poor man insert or update that works because transaction isolation level is serializable if _, err := tx.Exec("delete from runcounter_ost where groupid = $1", group); err != nil { - return errors.Errorf("failed to delete revision: %w", err) + return errors.Wrapf(err, "failed to delete revision") } // TODO(sgotti) go database/sql and mattn/sqlite3 don't support uint64 types... //q, args, err = revisionInsert.Values(int64(wresp.Header.ClusterId), run.Revision).ToSql() q, args, err := runcounterOSTInsert.Values(group, counter).ToSql() if err != nil { - return errors.Errorf("failed to build query: %w", err) + return errors.Wrapf(err, "failed to build query") } if _, err = tx.Exec(q, args...); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -1589,14 +1589,14 @@ func (r *ReadDB) GetRunCounterOST(tx *db.Tx, group string) (uint64, error) { q, args, err := runcounterOSTSelect.Where(sq.Eq{"groupid": group}).ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return 0, errors.Errorf("failed to build query: %w", err) + return 0, errors.Wrapf(err, "failed to build query") } err = tx.QueryRow(q, args...).Scan(&g, &counter) if errors.Is(err, sql.ErrNoRows) { return 0, nil } - return counter, err + return counter, errors.WithStack(err) } func (r *ReadDB) GetRunCountersOST(tx *db.Tx, start string, limit int) ([]*types.RunCounter, error) { @@ -1609,7 +1609,7 @@ func (r *ReadDB) GetRunCountersOST(tx *db.Tx, start string, limit int) ([]*types q, args, err := s.ToSql() r.log.Debug().Msgf("q: %s, args: %s", q, util.Dump(args)) if err != nil { - return nil, errors.Errorf("failed to build query: %w", err) + return nil, errors.Wrapf(err, "failed to build query") } return fetchRunCounters(tx, q, args...) @@ -1618,7 +1618,7 @@ func (r *ReadDB) GetRunCountersOST(tx *db.Tx, start string, limit int) ([]*types func fetchRunCounters(tx *db.Tx, q string, args ...interface{}) ([]*types.RunCounter, error) { rows, err := tx.Query(q, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer rows.Close() return scanRunCounters(rows) @@ -1627,7 +1627,7 @@ func fetchRunCounters(tx *db.Tx, q string, args ...interface{}) ([]*types.RunCou func scanRunCounter(rows *sql.Rows) (*types.RunCounter, error) { r := &types.RunCounter{} if err := rows.Scan(&r.Group, &r.Counter); err != nil { - return nil, errors.Errorf("failed to scan rows: %w", err) + return nil, errors.Wrapf(err, "failed to scan rows") } return r, nil @@ -1638,12 +1638,12 @@ func scanRunCounters(rows *sql.Rows) ([]*types.RunCounter, error) { for rows.Next() { r, err := scanRunCounter(rows) if err != nil { - return nil, err + return nil, errors.WithStack(err) } runCounters = append(runCounters, r) } if err := rows.Err(); err != nil { - return nil, err + return nil, errors.WithStack(err) } return runCounters, nil } diff --git a/internal/services/runservice/runservice.go b/internal/services/runservice/runservice.go index 9cdcf41..09503f0 100644 --- a/internal/services/runservice/runservice.go +++ b/internal/services/runservice/runservice.go @@ -24,6 +24,7 @@ import ( scommon "agola.io/agola/internal/common" "agola.io/agola/internal/datamanager" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/services/config" @@ -38,7 +39,6 @@ import ( "github.com/rs/zerolog" etcdclientv3 "go.etcd.io/etcd/clientv3" "go.etcd.io/etcd/mvcc/mvccpb" - errors "golang.org/x/xerrors" ) // etcdPingerLoop periodically updates a key. @@ -63,7 +63,7 @@ func (s *Runservice) etcdPingerLoop(ctx context.Context) { func (s *Runservice) etcdPinger(ctx context.Context) error { if _, err := s.e.Put(ctx, common.EtcdPingKey, []byte{}, nil); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -90,7 +90,7 @@ func (s *Runservice) maintenanceModeWatcher(ctx context.Context, runCtxCancel co s.log.Info().Msgf("watcher: maintenance mode enabled: %t", maintenanceModeEnabled) resp, err := s.e.Get(ctx, common.EtcdMaintenanceKey, 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if len(resp.Kvs) > 0 { @@ -109,7 +109,7 @@ func (s *Runservice) maintenanceModeWatcher(ctx context.Context, runCtxCancel co for wresp := range wch { if wresp.Canceled { - return wresp.Err() + return errors.WithStack(wresp.Err()) } for _, ev := range wresp.Events { @@ -150,11 +150,11 @@ func NewRunservice(ctx context.Context, log zerolog.Logger, c *config.Runservice ost, err := scommon.NewObjectStorage(&c.ObjectStorage) if err != nil { - return nil, err + return nil, errors.WithStack(err) } e, err := scommon.NewEtcd(&c.Etcd, log, "runservice") if err != nil { - return nil, err + return nil, errors.WithStack(err) } s := &Runservice{ @@ -176,13 +176,13 @@ func NewRunservice(ctx context.Context, log zerolog.Logger, c *config.Runservice } dm, err := datamanager.NewDataManager(ctx, log, dmConf) if err != nil { - return nil, err + return nil, errors.WithStack(err) } s.dm = dm readDB, err := readdb.NewReadDB(ctx, log, filepath.Join(c.DataDir, "readdb"), e, ost, dm) if err != nil { - return nil, err + return nil, errors.WithStack(err) } s.readDB = readDB @@ -201,7 +201,7 @@ func (s *Runservice) InitEtcd(ctx context.Context) error { then = append(then, etcdclientv3.OpPut(common.EtcdChangeGroupMinRevisionKey, "")) txn := s.e.Client().Txn(ctx).If(cmp...).Then(then...) if _, err := txn.Commit(); err != nil { - return etcd.FromEtcdError(err) + return errors.WithStack(etcd.FromEtcdError(err)) } return nil @@ -318,13 +318,13 @@ func (s *Runservice) run(ctx context.Context) error { tlsConfig, err = util.NewTLSConfig(s.c.Web.TLSCertFile, s.c.Web.TLSKeyFile, "", false) if err != nil { s.log.Err(err).Send() - return err + return errors.WithStack(err) } } resp, err := s.e.Get(ctx, common.EtcdMaintenanceKey, 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } maintenanceMode := false @@ -420,5 +420,5 @@ func (s *Runservice) run(ctx context.Context) error { httpServer.Close() wg.Wait() - return err + return errors.WithStack(err) } diff --git a/internal/services/runservice/scheduler.go b/internal/services/runservice/scheduler.go index d7d64ad..9ad04cc 100644 --- a/internal/services/runservice/scheduler.go +++ b/internal/services/runservice/scheduler.go @@ -24,6 +24,7 @@ import ( "time" "agola.io/agola/internal/datamanager" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/runconfig" @@ -35,7 +36,6 @@ import ( etcdclientv3 "go.etcd.io/etcd/clientv3" "go.etcd.io/etcd/clientv3/concurrency" - errors "golang.org/x/xerrors" ) const ( @@ -234,7 +234,7 @@ func (s *Runservice) submitRunTasks(ctx context.Context, r *types.Run, rc *types executor, err := s.chooseExecutor(ctx, rct) if err != nil { - return err + return errors.WithStack(err) } if executor == nil { s.log.Warn().Msgf("cannot choose an executor") @@ -249,16 +249,16 @@ func (s *Runservice) submitRunTasks(ctx context.Context, r *types.Run, rc *types // atomicPutExecutorTask will fail if it already exists tet, err := store.GetExecutorTask(ctx, s.e, et.ID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if tet != nil { continue } if _, err := store.AtomicPutExecutorTask(ctx, s.e, et); err != nil { - return err + return errors.WithStack(err) } if err := s.sendExecutorTask(ctx, et); err != nil { - return err + return errors.WithStack(err) } } @@ -270,13 +270,13 @@ func (s *Runservice) submitRunTasks(ctx context.Context, r *types.Run, rc *types func (s *Runservice) chooseExecutor(ctx context.Context, rct *types.RunConfigTask) (*types.Executor, error) { executors, err := store.GetExecutors(ctx, s.e) if err != nil { - return nil, err + return nil, errors.WithStack(err) } // TODO(sgotti) find a way to avoid retrieving this for every chooseExecutor // invocation (i.e. use an etcd watcher to keep this value updated) executorTasksCount, err := store.GetExecutorTasksCountByExecutor(ctx, s.e) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return chooseExecutor(executors, executorTasksCount, rct), nil } @@ -337,7 +337,7 @@ func chooseExecutor(executors []*types.Executor, executorTasksCount map[string]i func (s *Runservice) sendExecutorTask(ctx context.Context, et *types.ExecutorTask) error { executor, err := store.GetExecutor(ctx, s.e, et.Spec.ExecutorID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if executor == nil { s.log.Warn().Msgf("executor with id %q doesn't exist", et.Spec.ExecutorID) @@ -346,11 +346,11 @@ func (s *Runservice) sendExecutorTask(ctx context.Context, et *types.ExecutorTas r, _, err := store.GetRun(ctx, s.e, et.Spec.RunID) if err != nil { - return err + return errors.WithStack(err) } rc, err := store.OSTGetRunConfig(s.dm, r.ID) if err != nil { - return errors.Errorf("cannot get run config %q: %w", r.ID, err) + return errors.Wrapf(err, "cannot get run config %q", r.ID) } rt, ok := r.Tasks[et.ID] if !ok { @@ -365,12 +365,12 @@ func (s *Runservice) sendExecutorTask(ctx context.Context, et *types.ExecutorTas etj, err := json.Marshal(et) if err != nil { - return err + return errors.WithStack(err) } req, err := http.Post(executor.ListenURL+"/api/v1alpha/executor", "", bytes.NewReader(etj)) if err != nil { - return err + return errors.WithStack(err) } if req.StatusCode != http.StatusOK { return errors.Errorf("received http status: %d", req.StatusCode) @@ -397,7 +397,7 @@ func (s *Runservice) compactChangeGroupsLoop(ctx context.Context) { func (s *Runservice) compactChangeGroups(ctx context.Context) error { session, err := concurrency.NewSession(s.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -407,13 +407,13 @@ func (s *Runservice) compactChangeGroups(ctx context.Context) error { if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() resp, err := s.e.Client().Get(ctx, common.EtcdChangeGroupMinRevisionKey) if err != nil { - return err + return errors.WithStack(err) } revision := resp.Kvs[0].ModRevision @@ -424,7 +424,7 @@ func (s *Runservice) compactChangeGroups(ctx context.Context) error { txn := s.e.Client().Txn(ctx).If(cmp).Then(then) tresp, err := txn.Commit() if err != nil { - return etcd.FromEtcdError(err) + return errors.WithStack(etcd.FromEtcdError(err)) } if !tresp.Succeeded { return errors.Errorf("failed to update change group min revision key due to concurrent update") @@ -437,7 +437,7 @@ func (s *Runservice) compactChangeGroups(ctx context.Context) error { resp, err = s.e.List(ctx, common.EtcdChangeGroupsDir, "", 0) if err != nil { - return err + return errors.WithStack(err) } for _, kv := range resp.Kvs { if kv.ModRevision < revision-common.EtcdChangeGroupMinRevisionRange { @@ -446,7 +446,7 @@ func (s *Runservice) compactChangeGroups(ctx context.Context) error { txn := s.e.Client().Txn(ctx).If(cmp).Then(then) tresp, err := txn.Commit() if err != nil { - return etcd.FromEtcdError(err) + return errors.WithStack(etcd.FromEtcdError(err)) } if !tresp.Succeeded { s.log.Error().Msgf("failed to update change group min revision key due to concurrent update") @@ -468,11 +468,11 @@ func (s *Runservice) scheduleRun(ctx context.Context, r *types.Run, rc *types.Ru // executor tasks scheduled and running scheduledExecutorTasks, err := store.GetExecutorTasksForRun(ctx, s.e, r.ID) if err != nil { - return err + return errors.WithStack(err) } if err := advanceRun(ctx, s.log, r, rc, scheduledExecutorTasks); err != nil { - return err + return errors.WithStack(err) } var runEvent *types.RunEvent @@ -481,13 +481,13 @@ func (s *Runservice) scheduleRun(ctx context.Context, r *types.Run, rc *types.Ru var err error runEvent, err = common.NewRunEvent(ctx, s.e, r.ID, r.Phase, r.Result) if err != nil { - return err + return errors.WithStack(err) } } r, err = store.AtomicPutRun(ctx, s.e, r, runEvent, nil) if err != nil { - return err + return errors.WithStack(err) } // if the run is set to stop, stop all active tasks @@ -495,10 +495,10 @@ func (s *Runservice) scheduleRun(ctx context.Context, r *types.Run, rc *types.Ru for _, et := range scheduledExecutorTasks { et.Spec.Stop = true if _, err := store.AtomicPutExecutorTask(ctx, s.e, et); err != nil { - return err + return errors.WithStack(err) } if err := s.sendExecutorTask(ctx, et); err != nil { - return err + return errors.WithStack(err) } } } @@ -507,16 +507,16 @@ func (s *Runservice) scheduleRun(ctx context.Context, r *types.Run, rc *types.Ru if r.Phase == types.RunPhaseRunning { r, err := advanceRunTasks(ctx, s.log, r, rc, scheduledExecutorTasks) if err != nil { - return err + return errors.WithStack(err) } r, err = store.AtomicPutRun(ctx, s.e, r, nil, nil) if err != nil { - return err + return errors.WithStack(err) } tasksToRun, err := getTasksToRun(ctx, s.log, r, rc) if err != nil { - return err + return errors.WithStack(err) } return s.submitRunTasks(ctx, r, rc, tasksToRun) @@ -610,19 +610,19 @@ func advanceRun(ctx context.Context, log zerolog.Logger, r *types.Run, rc *types func (s *Runservice) handleExecutorTaskUpdate(ctx context.Context, et *types.ExecutorTask) error { r, _, err := store.GetRun(ctx, s.e, et.Spec.RunID) if err != nil { - return err + return errors.WithStack(err) } rc, err := store.OSTGetRunConfig(s.dm, r.ID) if err != nil { - return errors.Errorf("cannot get run config %q: %w", r.ID, err) + return errors.Wrapf(err, "cannot get run config %q", r.ID) } if err := s.updateRunTaskStatus(ctx, et, r); err != nil { - return err + return errors.WithStack(err) } r, err = store.AtomicPutRun(ctx, s.e, r, nil, nil) if err != nil { - return err + return errors.WithStack(err) } return s.scheduleRun(ctx, r, rc) @@ -746,7 +746,7 @@ func (s *Runservice) executorTasksCleaner(ctx context.Context) error { // TODO(sgotti) use paged List resp, err := s.e.List(ctx, common.EtcdTasksDir, "", 0) if err != nil { - return err + return errors.WithStack(err) } for _, kv := range resp.Kvs { @@ -773,12 +773,12 @@ func (s *Runservice) executorTaskCleaner(ctx context.Context, et *types.Executor // run doesn't exists, remove executor task if err := store.DeleteExecutorTask(ctx, s.e, et.ID); err != nil { s.log.Err(err).Send() - return err + return errors.WithStack(err) } return nil } s.log.Err(err).Send() - return err + return errors.WithStack(err) } if r.Phase.IsFinished() { @@ -786,11 +786,11 @@ func (s *Runservice) executorTaskCleaner(ctx context.Context, et *types.Executor if !et.Spec.Stop { et.Spec.Stop = true if _, err := store.AtomicPutExecutorTask(ctx, s.e, et); err != nil { - return err + return errors.WithStack(err) } if err := s.sendExecutorTask(ctx, et); err != nil { s.log.Err(err).Send() - return err + return errors.WithStack(err) } } } @@ -800,7 +800,7 @@ func (s *Runservice) executorTaskCleaner(ctx context.Context, et *types.Executor // if the executor doesn't exists anymore mark the not finished executor tasks as failed executor, err := store.GetExecutor(ctx, s.e, et.Spec.ExecutorID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if executor == nil { s.log.Warn().Msgf("executor with id %q doesn't exist. marking executor task %q as failed", et.Spec.ExecutorID, et.ID) @@ -814,7 +814,7 @@ func (s *Runservice) executorTaskCleaner(ctx context.Context, et *types.Executor } } if _, err := store.AtomicPutExecutorTask(ctx, s.e, et); err != nil { - return err + return errors.WithStack(err) } } } @@ -843,7 +843,7 @@ func (s *Runservice) runTasksUpdater(ctx context.Context) error { session, err := concurrency.NewSession(s.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -853,20 +853,20 @@ func (s *Runservice) runTasksUpdater(ctx context.Context) error { if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() // TODO(sgotti) use paged List resp, err := s.e.List(ctx, common.EtcdTasksDir, "", 0) if err != nil { - return err + return errors.WithStack(err) } for _, kv := range resp.Kvs { var et *types.ExecutorTask if err := json.Unmarshal(kv.Value, &et); err != nil { - return err + return errors.WithStack(err) } et.Revision = kv.ModRevision if err := s.handleExecutorTaskUpdate(ctx, et); err != nil { @@ -880,7 +880,7 @@ func (s *Runservice) runTasksUpdater(ctx context.Context) error { func (s *Runservice) OSTFileExists(path string) (bool, error) { _, err := s.ost.Stat(path) if err != nil && !objectstorage.IsNotExist(err) { - return false, err + return false, errors.WithStack(err) } return err == nil, nil } @@ -888,7 +888,7 @@ func (s *Runservice) OSTFileExists(path string) (bool, error) { func (s *Runservice) fetchLog(ctx context.Context, rt *types.RunTask, setup bool, stepnum int) error { et, err := store.GetExecutorTask(ctx, s.e, rt.ID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if et == nil { if rt.Status != types.RunTaskStatusSkipped { @@ -898,7 +898,7 @@ func (s *Runservice) fetchLog(ctx context.Context, rt *types.RunTask, setup bool } executor, err := store.GetExecutor(ctx, s.e, et.Spec.ExecutorID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if executor == nil { s.log.Warn().Msgf("executor with id %q doesn't exist. Skipping fetching", et.Spec.ExecutorID) @@ -913,7 +913,7 @@ func (s *Runservice) fetchLog(ctx context.Context, rt *types.RunTask, setup bool } ok, err := s.OSTFileExists(logPath) if err != nil { - return err + return errors.WithStack(err) } if ok { return nil @@ -927,7 +927,7 @@ func (s *Runservice) fetchLog(ctx context.Context, rt *types.RunTask, setup bool } r, err := http.Get(u) if err != nil { - return err + return errors.WithStack(err) } defer r.Body.Close() @@ -948,13 +948,13 @@ func (s *Runservice) fetchLog(ctx context.Context, rt *types.RunTask, setup bool } } - return s.ost.WriteObject(logPath, r.Body, size, false) + return errors.WithStack(s.ost.WriteObject(logPath, r.Body, size, false)) } func (s *Runservice) finishSetupLogPhase(ctx context.Context, runID, runTaskID string) error { r, _, err := store.GetRun(ctx, s.e, runID) if err != nil { - return err + return errors.WithStack(err) } rt, ok := r.Tasks[runTaskID] if !ok { @@ -963,7 +963,7 @@ func (s *Runservice) finishSetupLogPhase(ctx context.Context, runID, runTaskID s rt.SetupStep.LogPhase = types.RunTaskFetchPhaseFinished if _, err := store.AtomicPutRun(ctx, s.e, r, nil, nil); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -971,7 +971,7 @@ func (s *Runservice) finishSetupLogPhase(ctx context.Context, runID, runTaskID s func (s *Runservice) finishStepLogPhase(ctx context.Context, runID, runTaskID string, stepnum int) error { r, _, err := store.GetRun(ctx, s.e, runID) if err != nil { - return err + return errors.WithStack(err) } rt, ok := r.Tasks[runTaskID] if !ok { @@ -983,7 +983,7 @@ func (s *Runservice) finishStepLogPhase(ctx context.Context, runID, runTaskID st rt.Steps[stepnum].LogPhase = types.RunTaskFetchPhaseFinished if _, err := store.AtomicPutRun(ctx, s.e, r, nil, nil); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -991,7 +991,7 @@ func (s *Runservice) finishStepLogPhase(ctx context.Context, runID, runTaskID st func (s *Runservice) finishArchivePhase(ctx context.Context, runID, runTaskID string, stepnum int) error { r, _, err := store.GetRun(ctx, s.e, runID) if err != nil { - return err + return errors.WithStack(err) } rt, ok := r.Tasks[runTaskID] if !ok { @@ -1013,7 +1013,7 @@ func (s *Runservice) finishArchivePhase(ctx context.Context, runID, runTaskID st } if _, err := store.AtomicPutRun(ctx, s.e, r, nil, nil); err != nil { - return err + return errors.WithStack(err) } return nil } @@ -1051,7 +1051,7 @@ func (s *Runservice) fetchTaskLogs(ctx context.Context, runID string, rt *types. func (s *Runservice) fetchArchive(ctx context.Context, rt *types.RunTask, stepnum int) error { et, err := store.GetExecutorTask(ctx, s.e, rt.ID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if et == nil { if rt.Status != types.RunTaskStatusSkipped { @@ -1061,7 +1061,7 @@ func (s *Runservice) fetchArchive(ctx context.Context, rt *types.RunTask, stepnu } executor, err := store.GetExecutor(ctx, s.e, et.Spec.ExecutorID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } if executor == nil { s.log.Warn().Msgf("executor with id %q doesn't exist. Skipping fetching", et.Spec.ExecutorID) @@ -1071,7 +1071,7 @@ func (s *Runservice) fetchArchive(ctx context.Context, rt *types.RunTask, stepnu path := store.OSTRunTaskArchivePath(rt.ID, stepnum) ok, err := s.OSTFileExists(path) if err != nil { - return err + return errors.WithStack(err) } if ok { return nil @@ -1081,7 +1081,7 @@ func (s *Runservice) fetchArchive(ctx context.Context, rt *types.RunTask, stepnu s.log.Debug().Msgf("fetchArchive: %s", u) r, err := http.Get(u) if err != nil { - return err + return errors.WithStack(err) } defer r.Body.Close() @@ -1102,7 +1102,7 @@ func (s *Runservice) fetchArchive(ctx context.Context, rt *types.RunTask, stepnu } } - return s.ost.WriteObject(path, r.Body, size, false) + return errors.WithStack(s.ost.WriteObject(path, r.Body, size, false)) } func (s *Runservice) fetchTaskArchives(ctx context.Context, runID string, rt *types.RunTask) { @@ -1144,14 +1144,14 @@ func (s *Runservice) fetcher(ctx context.Context) error { s.log.Debug().Msgf("fetcher") runs, err := store.GetRuns(ctx, s.e) if err != nil { - return err + return errors.WithStack(err) } for _, r := range runs { s.log.Debug().Msgf("r: %s", util.Dump(r)) for _, rt := range r.Tasks { s.log.Debug().Msgf("rt: %s", util.Dump(rt)) if err := s.taskFetcher(ctx, r, rt); err != nil { - return err + return errors.WithStack(err) } } } @@ -1165,7 +1165,7 @@ func (s *Runservice) taskFetcher(ctx context.Context, r *types.Run, rt *types.Ru } session, err := concurrency.NewSession(s.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -1175,7 +1175,7 @@ func (s *Runservice) taskFetcher(ctx context.Context, r *types.Run, rt *types.Ru if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() @@ -1209,7 +1209,7 @@ func (s *Runservice) taskFetcher(ctx context.Context, r *types.Run, rt *types.Ru // should fetch the data if rt.LogsFetchFinished() && rt.ArchivesFetchFinished() { if err := store.DeleteExecutorTask(ctx, s.e, rt.ID); err != nil { - return err + return errors.WithStack(err) } } @@ -1237,7 +1237,7 @@ func (s *Runservice) runsScheduler(ctx context.Context) error { s.log.Debug().Msgf("runsScheduler") runs, err := store.GetRuns(ctx, s.e) if err != nil { - return err + return errors.WithStack(err) } for _, r := range runs { if err := s.runScheduler(ctx, r); err != nil { @@ -1252,7 +1252,7 @@ func (s *Runservice) runScheduler(ctx context.Context, r *types.Run) error { s.log.Debug().Msgf("runScheduler") rc, err := store.OSTGetRunConfig(s.dm, r.ID) if err != nil { - return errors.Errorf("cannot get run config %q: %w", r.ID, err) + return errors.Wrapf(err, "cannot get run config %q", r.ID) } return s.scheduleRun(ctx, r, rc) @@ -1279,7 +1279,7 @@ func (s *Runservice) finishedRunsArchiver(ctx context.Context) error { s.log.Debug().Msgf("finished run archiver") runs, err := store.GetRuns(ctx, s.e) if err != nil { - return err + return errors.WithStack(err) } for _, r := range runs { if err := s.finishedRunArchiver(ctx, r); err != nil { @@ -1290,7 +1290,7 @@ func (s *Runservice) finishedRunsArchiver(ctx context.Context) error { // We write archived runs in objectstorage in the ordered they were archived runs, err = store.GetRuns(ctx, s.e) if err != nil { - return err + return errors.WithStack(err) } for _, r := range runs { if r.Archived { @@ -1330,7 +1330,7 @@ func (s *Runservice) finishedRunArchiver(ctx context.Context, r *types.Run) erro r.Archived = true if _, err := store.AtomicPutRun(ctx, s.e, r, nil, nil); err != nil { - return err + return errors.WithStack(err) } return nil @@ -1342,18 +1342,18 @@ func (s *Runservice) runOSTArchiver(ctx context.Context, r *types.Run) error { s.log.Info().Msgf("saving run in objectstorage: %s", r.ID) ra, err := store.OSTSaveRunAction(r) if err != nil { - return err + return errors.WithStack(err) } actions := []*datamanager.Action{ra} if _, err = s.dm.WriteWal(ctx, actions, nil); err != nil { - return err + return errors.WithStack(err) } s.log.Info().Msgf("deleting run from etcd: %s", r.ID) if err := store.DeleteRun(ctx, s.e, r.ID); err != nil { - return err + return errors.WithStack(err) } return nil @@ -1379,7 +1379,7 @@ func (s *Runservice) cacheCleaner(ctx context.Context, cacheExpireInterval time. session, err := concurrency.NewSession(s.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -1389,7 +1389,7 @@ func (s *Runservice) cacheCleaner(ctx context.Context, cacheExpireInterval time. if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() @@ -1397,7 +1397,7 @@ func (s *Runservice) cacheCleaner(ctx context.Context, cacheExpireInterval time. defer close(doneCh) for object := range s.ost.List(store.OSTCacheDir()+"/", "", true, doneCh) { if object.Err != nil { - return object.Err + return errors.WithStack(object.Err) } if object.LastModified.Add(cacheExpireInterval).Before(time.Now()) { if err := s.ost.DeleteObject(object.Path); err != nil { @@ -1431,7 +1431,7 @@ func (s *Runservice) workspaceCleaner(ctx context.Context, workspaceExpireInterv session, err := concurrency.NewSession(s.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) if err != nil { - return err + return errors.WithStack(err) } defer session.Close() @@ -1441,7 +1441,7 @@ func (s *Runservice) workspaceCleaner(ctx context.Context, workspaceExpireInterv if errors.Is(err, etcd.ErrLocked) { return nil } - return err + return errors.WithStack(err) } defer func() { _ = m.Unlock(ctx) }() @@ -1449,7 +1449,7 @@ func (s *Runservice) workspaceCleaner(ctx context.Context, workspaceExpireInterv defer close(doneCh) for object := range s.ost.List(store.OSTArchivesBaseDir()+"/", "", true, doneCh) { if object.Err != nil { - return object.Err + return errors.WithStack(object.Err) } if object.LastModified.Add(workspaceExpireInterval).Before(time.Now()) { if err := s.ost.DeleteObject(object.Path); err != nil { diff --git a/internal/services/runservice/store/store.go b/internal/services/runservice/store/store.go index e4e0ff9..8f28c97 100644 --- a/internal/services/runservice/store/store.go +++ b/internal/services/runservice/store/store.go @@ -23,13 +23,14 @@ import ( "strings" "agola.io/agola/internal/datamanager" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" + "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/services/runservice/common" "agola.io/agola/internal/util" "agola.io/agola/services/runservice/types" etcdclientv3 "go.etcd.io/etcd/clientv3" - errors "golang.org/x/xerrors" ) const ( @@ -45,7 +46,7 @@ func OSTUpdateRunCounterAction(ctx context.Context, c uint64, group string) (*da cj, err := json.Marshal(c) if err != nil { - return nil, err + return nil, errors.WithStack(err) } action := &datamanager.Action{ @@ -134,13 +135,13 @@ func OSTCacheKey(p string) string { func OSTGetRunConfig(dm *datamanager.DataManager, runConfigID string) (*types.RunConfig, error) { rcf, _, err := dm.ReadObject(string(common.DataTypeRunConfig), runConfigID, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer rcf.Close() d := json.NewDecoder(rcf) var rc *types.RunConfig if err := d.Decode(&rc); err != nil { - return nil, err + return nil, errors.WithStack(err) } return rc, nil @@ -149,7 +150,7 @@ func OSTGetRunConfig(dm *datamanager.DataManager, runConfigID string) (*types.Ru func OSTSaveRunConfigAction(rc *types.RunConfig) (*datamanager.Action, error) { rcj, err := json.Marshal(rc) if err != nil { - return nil, err + return nil, errors.WithStack(err) } action := &datamanager.Action{ @@ -165,13 +166,13 @@ func OSTSaveRunConfigAction(rc *types.RunConfig) (*datamanager.Action, error) { func OSTGetRun(dm *datamanager.DataManager, runID string) (*types.Run, error) { rf, _, err := dm.ReadObject(string(common.DataTypeRun), runID, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } defer rf.Close() d := json.NewDecoder(rf) var r *types.Run if err := d.Decode(&r); err != nil { - return nil, err + return nil, errors.WithStack(err) } return r, nil @@ -180,7 +181,7 @@ func OSTGetRun(dm *datamanager.DataManager, runID string) (*types.Run, error) { func OSTSaveRunAction(r *types.Run) (*datamanager.Action, error) { rj, err := json.Marshal(r) if err != nil { - return nil, err + return nil, errors.WithStack(err) } action := &datamanager.Action{ @@ -196,13 +197,13 @@ func OSTSaveRunAction(r *types.Run) (*datamanager.Action, error) { func GetExecutor(ctx context.Context, e *etcd.Store, executorID string) (*types.Executor, error) { resp, err := e.Get(ctx, common.EtcdExecutorKey(executorID), 0) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var executor *types.Executor kv := resp.Kvs[0] if err := json.Unmarshal(kv.Value, &executor); err != nil { - return nil, err + return nil, errors.WithStack(err) } executor.Revision = kv.ModRevision @@ -213,7 +214,7 @@ func GetExecutors(ctx context.Context, e *etcd.Store) ([]*types.Executor, error) // TODO(sgotti) use paged List resp, err := e.List(ctx, common.EtcdExecutorsDir, "", 0) if err != nil { - return nil, err + return nil, errors.WithStack(err) } executors := []*types.Executor{} @@ -221,7 +222,7 @@ func GetExecutors(ctx context.Context, e *etcd.Store) ([]*types.Executor, error) for _, kv := range resp.Kvs { var executor *types.Executor if err := json.Unmarshal(kv.Value, &executor); err != nil { - return nil, err + return nil, errors.WithStack(err) } executor.Revision = kv.ModRevision executors = append(executors, executor) @@ -233,12 +234,12 @@ func GetExecutors(ctx context.Context, e *etcd.Store) ([]*types.Executor, error) func PutExecutor(ctx context.Context, e *etcd.Store, executor *types.Executor) (*types.Executor, error) { executorj, err := json.Marshal(executor) if err != nil { - return nil, err + return nil, errors.WithStack(err) } resp, err := e.Put(ctx, common.EtcdExecutorKey(executor.ID), executorj, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } executor.Revision = resp.Header.Revision @@ -246,19 +247,19 @@ func PutExecutor(ctx context.Context, e *etcd.Store, executor *types.Executor) ( } func DeleteExecutor(ctx context.Context, e *etcd.Store, executorID string) error { - return e.Delete(ctx, common.EtcdExecutorKey(executorID)) + return errors.WithStack(e.Delete(ctx, common.EtcdExecutorKey(executorID))) } func GetExecutorTask(ctx context.Context, e *etcd.Store, etID string) (*types.ExecutorTask, error) { resp, err := e.Get(ctx, common.EtcdTaskKey(etID), 0) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var et *types.ExecutorTask kv := resp.Kvs[0] if err := json.Unmarshal(kv.Value, &et); err != nil { - return nil, err + return nil, errors.WithStack(err) } et.Revision = kv.ModRevision @@ -268,12 +269,12 @@ func GetExecutorTask(ctx context.Context, e *etcd.Store, etID string) (*types.Ex func AtomicPutExecutorTask(ctx context.Context, e *etcd.Store, et *types.ExecutorTask) (*types.ExecutorTask, error) { etj, err := json.Marshal(et) if err != nil { - return nil, err + return nil, errors.WithStack(err) } resp, err := e.AtomicPut(ctx, common.EtcdTaskKey(et.ID), etj, et.Revision, nil) if err != nil { - return nil, err + return nil, errors.WithStack(err) } et.Revision = resp.Header.Revision @@ -283,7 +284,7 @@ func AtomicPutExecutorTask(ctx context.Context, e *etcd.Store, et *types.Executo func UpdateExecutorTaskStatus(ctx context.Context, e *etcd.Store, et *types.ExecutorTask) (*types.ExecutorTask, error) { curEt, err := GetExecutorTask(ctx, e, et.ID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } //if curET.Revision >= et.Revision { @@ -295,14 +296,14 @@ func UpdateExecutorTaskStatus(ctx context.Context, e *etcd.Store, et *types.Exec } func DeleteExecutorTask(ctx context.Context, e *etcd.Store, etID string) error { - return e.Delete(ctx, common.EtcdTaskKey(etID)) + return errors.WithStack(e.Delete(ctx, common.EtcdTaskKey(etID))) } func GetExecutorTasksCountByExecutor(ctx context.Context, e *etcd.Store) (map[string]int, error) { // TODO(sgotti) use paged List resp, err := e.List(ctx, common.EtcdTasksDir, "", 0) if err != nil { - return nil, err + return nil, errors.WithStack(err) } count := map[string]int{} @@ -310,7 +311,7 @@ func GetExecutorTasksCountByExecutor(ctx context.Context, e *etcd.Store) (map[st for _, kv := range resp.Kvs { var et *types.ExecutorTask if err := json.Unmarshal(kv.Value, &et); err != nil { - return nil, err + return nil, errors.WithStack(err) } count[et.Spec.ExecutorID] = count[et.Spec.ExecutorID] + 1 } @@ -322,7 +323,7 @@ func GetExecutorTasksForExecutor(ctx context.Context, e *etcd.Store, executorID // TODO(sgotti) use paged List resp, err := e.List(ctx, common.EtcdTasksDir, "", 0) if err != nil { - return nil, err + return nil, errors.WithStack(err) } ets := []*types.ExecutorTask{} @@ -330,7 +331,7 @@ func GetExecutorTasksForExecutor(ctx context.Context, e *etcd.Store, executorID for _, kv := range resp.Kvs { var et *types.ExecutorTask if err := json.Unmarshal(kv.Value, &et); err != nil { - return nil, err + return nil, errors.WithStack(err) } et.Revision = kv.ModRevision if et.Spec.ExecutorID == executorID { @@ -344,7 +345,7 @@ func GetExecutorTasksForExecutor(ctx context.Context, e *etcd.Store, executorID func GetExecutorTasksForRun(ctx context.Context, e *etcd.Store, runID string) ([]*types.ExecutorTask, error) { r, curRevision, err := GetRun(ctx, e, runID) if err != nil { - return nil, err + return nil, errors.WithStack(err) } rtIDs := make([]string, len(r.Tasks)) @@ -369,7 +370,7 @@ func GetExecutorTasksForRun(ctx context.Context, e *etcd.Store, runID string) ([ txn := e.Client().Txn(ctx).Then(then...) tresp, err := txn.Commit() if err != nil { - return nil, etcd.FromEtcdError(err) + return nil, errors.WithStack(etcd.FromEtcdError(err)) } for _, resp := range tresp.Responses { if len(resp.GetResponseRange().Kvs) == 0 { @@ -378,7 +379,7 @@ func GetExecutorTasksForRun(ctx context.Context, e *etcd.Store, runID string) ([ kv := resp.GetResponseRange().Kvs[0] var et *types.ExecutorTask if err := json.Unmarshal(kv.Value, &et); err != nil { - return nil, err + return nil, errors.WithStack(err) } et.Revision = kv.ModRevision ets = append(ets, et) @@ -391,13 +392,13 @@ func GetExecutorTasksForRun(ctx context.Context, e *etcd.Store, runID string) ([ func GetRun(ctx context.Context, e *etcd.Store, runID string) (*types.Run, int64, error) { resp, err := e.Get(ctx, common.EtcdRunKey(runID), 0) if err != nil { - return nil, 0, err + return nil, 0, errors.WithStack(err) } var r *types.Run kv := resp.Kvs[0] if err := json.Unmarshal(kv.Value, &r); err != nil { - return nil, 0, err + return nil, 0, errors.WithStack(err) } r.Revision = kv.ModRevision @@ -409,10 +410,10 @@ func AtomicPutRun(ctx context.Context, e *etcd.Store, r *types.Run, runEvent *ty if cgt != nil { for cgName := range cgt.ChangeGroupsRevisions { if strings.Contains(cgName, "/") { - return nil, fmt.Errorf(`changegroup name %q must not contain "/"`, cgName) + return nil, errors.Errorf(`changegroup name %q must not contain "/"`, cgName) } if len(cgName) > MaxChangegroupNameLength { - return nil, fmt.Errorf("changegroup name %q too long", cgName) + return nil, errors.Errorf("changegroup name %q too long", cgName) } } } @@ -420,7 +421,7 @@ func AtomicPutRun(ctx context.Context, e *etcd.Store, r *types.Run, runEvent *ty // insert only if the run as changed curRun, _, err := GetRun(ctx, e, r.ID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return nil, err + return nil, errors.WithStack(err) } if !errors.Is(err, etcd.ErrKeyNotFound) { if curRun.Revision != r.Revision { @@ -434,7 +435,7 @@ func AtomicPutRun(ctx context.Context, e *etcd.Store, r *types.Run, runEvent *ty rj, err := json.Marshal(r) if err != nil { - return nil, err + return nil, errors.WithStack(err) } hasOptimisticLocking := false @@ -472,7 +473,7 @@ func AtomicPutRun(ctx context.Context, e *etcd.Store, r *types.Run, runEvent *ty if runEvent != nil { eventj, err := json.Marshal(runEvent) if err != nil { - return nil, err + return nil, errors.WithStack(err) } then = append(then, etcdclientv3.OpPut(common.EtcdRunEventKey, string(eventj))) } @@ -480,7 +481,7 @@ func AtomicPutRun(ctx context.Context, e *etcd.Store, r *types.Run, runEvent *ty txn := e.Client().Txn(ctx).If(cmp...).Then(then...) tresp, err := txn.Commit() if err != nil { - return nil, etcd.FromEtcdError(err) + return nil, errors.WithStack(etcd.FromEtcdError(err)) } if !tresp.Succeeded { if hasOptimisticLocking { @@ -495,14 +496,14 @@ func AtomicPutRun(ctx context.Context, e *etcd.Store, r *types.Run, runEvent *ty } func DeleteRun(ctx context.Context, e *etcd.Store, runID string) error { - return e.Delete(ctx, common.EtcdRunKey(runID)) + return errors.WithStack(e.Delete(ctx, common.EtcdRunKey(runID))) } func GetRuns(ctx context.Context, e *etcd.Store) ([]*types.Run, error) { // TODO(sgotti) use paged List resp, err := e.List(ctx, common.EtcdRunsDir, "", 0) if err != nil { - return nil, err + return nil, errors.WithStack(err) } runs := []*types.Run{} @@ -510,7 +511,7 @@ func GetRuns(ctx context.Context, e *etcd.Store) ([]*types.Run, error) { for _, kv := range resp.Kvs { var r *types.Run if err := json.Unmarshal(kv.Value, &r); err != nil { - return nil, err + return nil, errors.WithStack(err) } r.Revision = kv.ModRevision runs = append(runs, r) @@ -522,12 +523,12 @@ func GetRuns(ctx context.Context, e *etcd.Store) ([]*types.Run, error) { func GetRunEtcdOrOST(ctx context.Context, e *etcd.Store, dm *datamanager.DataManager, runID string) (*types.Run, error) { r, _, err := GetRun(ctx, e, runID) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return nil, err + return nil, errors.WithStack(err) } if r == nil { r, err = OSTGetRun(dm, runID) - if err != nil && !datamanager.IsNotExist(err) { - return nil, err + if err != nil && !objectstorage.IsNotExist(err) { + return nil, errors.WithStack(err) } } diff --git a/internal/services/runservice/store/store_test.go b/internal/services/runservice/store/store_test.go index 33fbf4e..ad9a980 100644 --- a/internal/services/runservice/store/store_test.go +++ b/internal/services/runservice/store/store_test.go @@ -15,8 +15,9 @@ package store import ( - "fmt" "testing" + + "agola.io/agola/internal/errors" ) func TestOSTRunTaskIDFromArchivePath(t *testing.T) { @@ -29,17 +30,17 @@ func TestOSTRunTaskIDFromArchivePath(t *testing.T) { { name: "test no runs 1", archivePath: "aaaa", - err: fmt.Errorf("wrong archive path %q", "aaaa"), + err: errors.Errorf("wrong archive path %q", "aaaa"), }, { name: "test no runs 1", archivePath: "workspacearchives", - err: fmt.Errorf("wrong archive path %q", "workspacearchives"), + err: errors.Errorf("wrong archive path %q", "workspacearchives"), }, { name: "test no runs 1", archivePath: "/workspacearchives/", - err: fmt.Errorf("wrong archive path %q", "/workspacearchives/"), + err: errors.Errorf("wrong archive path %q", "/workspacearchives/"), }, { name: "test no runs 1", diff --git a/internal/services/scheduler/scheduler.go b/internal/services/scheduler/scheduler.go index ab1169f..d1d5fd8 100644 --- a/internal/services/scheduler/scheduler.go +++ b/internal/services/scheduler/scheduler.go @@ -20,6 +20,7 @@ import ( "fmt" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/common" "agola.io/agola/internal/services/config" "agola.io/agola/internal/util" @@ -28,7 +29,6 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" - errors "golang.org/x/xerrors" ) func (s *Scheduler) scheduleLoop(ctx context.Context) { @@ -54,7 +54,7 @@ func (s *Scheduler) schedule(ctx context.Context) error { for { queuedRunsResponse, _, err := s.runserviceClient.GetQueuedRuns(ctx, lastRunID, 0, nil) if err != nil { - return errors.Errorf("failed to get queued runs: %w", err) + return errors.Wrapf(err, "failed to get queued runs") } for _, run := range queuedRunsResponse.Runs { @@ -81,7 +81,7 @@ func (s *Scheduler) scheduleRun(ctx context.Context, groupID string) error { // get first queued run queuedRunsResponse, _, err := s.runserviceClient.GetGroupFirstQueuedRuns(ctx, groupID, nil) if err != nil { - return errors.Errorf("failed to get the first project queued run: %w", err) + return errors.Wrapf(err, "failed to get the first project queued run") } if len(queuedRunsResponse.Runs) == 0 { return nil @@ -92,7 +92,7 @@ func (s *Scheduler) scheduleRun(ctx context.Context, groupID string) error { changegroup := util.EncodeSha256Hex(fmt.Sprintf("changegroup-%s", groupID)) runningRunsResponse, _, err := s.runserviceClient.GetGroupRunningRuns(ctx, groupID, 1, []string{changegroup}) if err != nil { - return errors.Errorf("failed to get running runs: %w", err) + return errors.Wrapf(err, "failed to get running runs") } if len(runningRunsResponse.Runs) == 0 { log.Info().Msgf("starting run %s", run.ID) @@ -125,7 +125,7 @@ func (s *Scheduler) approve(ctx context.Context) error { for { runningRunsResponse, _, err := s.runserviceClient.GetRunningRuns(ctx, lastRunID, 0, nil) if err != nil { - return errors.Errorf("failed to get running runs: %w", err) + return errors.Wrapf(err, "failed to get running runs") } if len(runningRunsResponse.Runs) == 0 { @@ -150,7 +150,7 @@ func (s *Scheduler) approveRunTasks(ctx context.Context, runID string) error { changegroup := util.EncodeSha256Hex(fmt.Sprintf("approval-%s", runID)) runResp, _, err := s.runserviceClient.GetRun(ctx, runID, []string{changegroup}) if err != nil { - return errors.Errorf("failed to get run %q: %w", runID, err) + return errors.Wrapf(err, "failed to get run %q", runID) } run := runResp.Run @@ -170,7 +170,7 @@ func (s *Scheduler) approveRunTasks(ctx context.Context, runID string) error { } var approvers []string if err := json.Unmarshal([]byte(approversAnnotation), &approvers); err != nil { - return errors.Errorf("failed to unmarshal run task approvers annotation: %w", err) + return errors.Wrapf(err, "failed to unmarshal run task approvers annotation") } // TODO(sgotti) change when we introduce a config the set the minimum number of required approvers if len(approvers) > 0 { @@ -179,7 +179,7 @@ func (s *Scheduler) approveRunTasks(ctx context.Context, runID string) error { ChangeGroupsUpdateToken: runResp.ChangeGroupsUpdateToken, } if _, err := s.runserviceClient.RunTaskActions(ctx, run.ID, rt.ID, rsreq); err != nil { - return errors.Errorf("failed to approve run: %w", err) + return errors.Wrapf(err, "failed to approve run") } } } diff --git a/internal/testutil/env.go b/internal/testutil/env.go index 60abf9f..2707967 100644 --- a/internal/testutil/env.go +++ b/internal/testutil/env.go @@ -16,10 +16,11 @@ package testutil import ( "bufio" - "fmt" "io" "strings" "unicode" + + "agola.io/agola/internal/errors" ) func ParseEnv(envvar string) (string, string, error) { @@ -27,11 +28,11 @@ func ParseEnv(envvar string) (string, string, error) { envvar = strings.TrimLeftFunc(envvar, unicode.IsSpace) arr := strings.SplitN(envvar, "=", 2) if len(arr) == 0 { - return "", "", fmt.Errorf("invalid environment variable definition: %s", envvar) + return "", "", errors.Errorf("invalid environment variable definition: %s", envvar) } varname := arr[0] if varname == "" { - return "", "", fmt.Errorf("invalid environment variable definition: %s", envvar) + return "", "", errors.Errorf("invalid environment variable definition: %s", envvar) } if len(arr) == 1 { return varname, "", nil @@ -46,12 +47,12 @@ func ParseEnvs(r io.Reader) (map[string]string, error) { for scanner.Scan() { envname, envvalue, err := ParseEnv(scanner.Text()) if err != nil { - return nil, err + return nil, errors.WithStack(err) } envs[envname] = envvalue } if err := scanner.Err(); err != nil { - return nil, err + return nil, errors.WithStack(err) } return envs, nil diff --git a/internal/testutil/utils.go b/internal/testutil/utils.go index e285217..f0058fe 100644 --- a/internal/testutil/utils.go +++ b/internal/testutil/utils.go @@ -32,13 +32,13 @@ import ( "text/template" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/etcd" "github.com/rs/zerolog" "go.etcd.io/etcd/embed" "github.com/gofrs/uuid" "github.com/sgotti/gexpect" - errors "golang.org/x/xerrors" ) const ( @@ -63,16 +63,16 @@ type Process struct { func (p *Process) start() error { if p.Cmd != nil { - panic(fmt.Errorf("%s: cmd not cleanly stopped", p.uid)) + panic(errors.Errorf("%s: cmd not cleanly stopped", p.uid)) } cmd := exec.Command(p.bin, p.args...) pr, pw, err := os.Pipe() if err != nil { - return err + return errors.WithStack(err) } p.Cmd = &gexpect.ExpectSubprocess{Cmd: cmd, Output: pw} if err := p.Cmd.Start(); err != nil { - return err + return errors.WithStack(err) } go func() { scanner := bufio.NewScanner(pr) @@ -86,7 +86,7 @@ func (p *Process) start() error { func (p *Process) Start() error { if err := p.start(); err != nil { - return err + return errors.WithStack(err) } p.Cmd.Continue() return nil @@ -99,15 +99,15 @@ func (p *Process) StartExpect() error { func (p *Process) Signal(sig os.Signal) error { p.t.Logf("signalling %s %s with %s", p.name, p.uid, sig) if p.Cmd == nil { - panic(fmt.Errorf("p: %s, cmd is empty", p.uid)) + panic(errors.Errorf("p: %s, cmd is empty", p.uid)) } - return p.Cmd.Cmd.Process.Signal(sig) + return errors.WithStack(p.Cmd.Cmd.Process.Signal(sig)) } func (p *Process) Kill() { p.t.Logf("killing %s %s", p.name, p.uid) if p.Cmd == nil { - panic(fmt.Errorf("p: %s, cmd is empty", p.uid)) + panic(errors.Errorf("p: %s, cmd is empty", p.uid)) } _ = p.Cmd.Cmd.Process.Signal(os.Kill) _ = p.Cmd.Wait() @@ -117,7 +117,7 @@ func (p *Process) Kill() { func (p *Process) Stop() { p.t.Logf("stopping %s %s", p.name, p.uid) if p.Cmd == nil { - panic(fmt.Errorf("p: %s, cmd is empty", p.uid)) + panic(errors.Errorf("p: %s, cmd is empty", p.uid)) } p.Cmd.Continue() _ = p.Cmd.Cmd.Process.Signal(os.Interrupt) @@ -134,7 +134,7 @@ func (p *Process) Wait(timeout time.Duration) error { }() select { case <-timeoutCh: - return fmt.Errorf("timeout waiting on process") + return errors.Errorf("timeout waiting on process") case <-endCh: return nil } @@ -157,11 +157,11 @@ func NewTestEmbeddedEtcd(t *testing.T, log zerolog.Logger, dir string, a ...stri listenAddress, port, err := GetFreePort(true, false) if err != nil { - return nil, err + return nil, errors.WithStack(err) } listenAddress2, port2, err := GetFreePort(true, false) if err != nil { - return nil, err + return nil, errors.WithStack(err) } cfg := embed.NewConfig() @@ -183,7 +183,7 @@ func NewTestEmbeddedEtcd(t *testing.T, log zerolog.Logger, dir string, a ...stri t.Logf("starting embedded etcd server") embeddedEtcd, err := embed.StartEtcd(cfg) if err != nil { - return nil, err + return nil, errors.WithStack(err) } storeEndpoint := fmt.Sprintf("http://%s:%s", listenAddress, port) @@ -194,7 +194,7 @@ func NewTestEmbeddedEtcd(t *testing.T, log zerolog.Logger, dir string, a ...stri } e, err := etcd.New(storeConfig) if err != nil { - return nil, fmt.Errorf("cannot create store: %w", err) + return nil, errors.Wrapf(err, "cannot create store") } tectd := &TestEmbeddedEtcd{ @@ -243,11 +243,11 @@ func NewTestExternalEtcd(t *testing.T, log zerolog.Logger, dir string, a ...stri listenAddress, port, err := GetFreePort(true, false) if err != nil { - return nil, err + return nil, errors.WithStack(err) } listenAddress2, port2, err := GetFreePort(true, false) if err != nil { - return nil, err + return nil, errors.WithStack(err) } args := []string{} @@ -268,12 +268,12 @@ func NewTestExternalEtcd(t *testing.T, log zerolog.Logger, dir string, a ...stri } e, err := etcd.New(storeConfig) if err != nil { - return nil, fmt.Errorf("cannot create store: %w", err) + return nil, errors.Wrapf(err, "cannot create store") } bin := os.Getenv("ETCD_BIN") if bin == "" { - return nil, fmt.Errorf("missing ETCD_BIN env") + return nil, errors.Errorf("missing ETCD_BIN env") } tectd := &TestExternalEtcd{ t: t, @@ -305,11 +305,11 @@ func (te *TestEtcd) Compact() error { defer cancel() resp, err := te.Get(ctx, "anykey", 0) if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { - return err + return errors.WithStack(err) } _, err = te.Client().Compact(ctx, resp.Header.Revision) - return err + return errors.WithStack(err) } func (te *TestEtcd) WaitUp(timeout time.Duration) error { @@ -327,7 +327,7 @@ func (te *TestEtcd) WaitUp(timeout time.Duration) error { time.Sleep(sleepInterval) } - return fmt.Errorf("timeout") + return errors.Errorf("timeout") } func (te *TestEtcd) WaitDown(timeout time.Duration) error { @@ -342,7 +342,7 @@ func (te *TestEtcd) WaitDown(timeout time.Duration) error { time.Sleep(sleepInterval) } - return fmt.Errorf("timeout") + return errors.Errorf("timeout") } const ( @@ -483,22 +483,22 @@ func NewTestGitea(t *testing.T, dir, dockerBridgeAddress string, a ...string) (* } tmpl, err := template.New("gitea").Parse(giteaAppIniTmpl) if err != nil { - return nil, err + return nil, errors.WithStack(err) } conf := &bytes.Buffer{} if err := tmpl.Execute(conf, giteaConfig); err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := os.MkdirAll(filepath.Join(dir, "gitea", "conf"), 0775); err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := os.MkdirAll(filepath.Join(dir, "gitea", "log"), 0775); err != nil { - return nil, err + return nil, errors.WithStack(err) } configPath := filepath.Join(dir, "gitea", "conf", "app.ini") if err := ioutil.WriteFile(configPath, conf.Bytes(), 0664); err != nil { - return nil, err + return nil, errors.WithStack(err) } args := []string{} @@ -530,20 +530,20 @@ func Wait(timeout time.Duration, f CheckFunc) error { for time.Now().Add(-timeout).Before(start) { ok, err := f() if err != nil { - return err + return errors.WithStack(err) } if ok { return nil } time.Sleep(sleepInterval) } - return fmt.Errorf("timeout") + return errors.Errorf("timeout") } func testFreeTCPPort(port int) error { ln, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) if err != nil { - return err + return errors.WithStack(err) } ln.Close() return nil @@ -552,7 +552,7 @@ func testFreeTCPPort(port int) error { func testFreeUDPPort(port int) error { ln, err := net.ListenPacket("udp", fmt.Sprintf("localhost:%d", port)) if err != nil { - return err + return errors.WithStack(err) } ln.Close() return nil @@ -564,16 +564,16 @@ func GetFreePort(tcp bool, udp bool) (string, string, error) { defer portMutex.Unlock() if !tcp && !udp { - return "", "", fmt.Errorf("at least one of tcp or udp port shuld be required") + return "", "", errors.Errorf("at least one of tcp or udp port shuld be required") } localhostIP, err := net.ResolveIPAddr("ip", "localhost") if err != nil { - return "", "", fmt.Errorf("failed to resolve ip addr: %w", err) + return "", "", errors.Wrapf(err, "failed to resolve ip addr") } for { curPort++ if curPort > MaxPort { - return "", "", fmt.Errorf("all available ports to test have been exausted") + return "", "", errors.Errorf("all available ports to test have been exausted") } if tcp { if err := testFreeTCPPort(curPort); err != nil { diff --git a/internal/toolbox/archive/archive.go b/internal/toolbox/archive/archive.go index dfbc6a3..becfe33 100644 --- a/internal/toolbox/archive/archive.go +++ b/internal/toolbox/archive/archive.go @@ -16,13 +16,13 @@ package archive import ( "archive/tar" - "fmt" "io" "log" "os" "path" "path/filepath" + "agola.io/agola/internal/errors" "github.com/bmatcuk/doublestar" ) @@ -50,10 +50,10 @@ func CreateTar(archiveInfos []*ArchiveInfo, w io.Writer) error { sourceDirInfo, err := os.Stat(sourceDir) if err != nil { - return fmt.Errorf("%s: stat: %w", sourceDir, err) + return errors.Wrapf(err, "%s: stat", sourceDir) } if !sourceDirInfo.IsDir() { - return fmt.Errorf("sourceDir %q is not a directory", sourceDir) + return errors.Errorf("sourceDir %q is not a directory", sourceDir) } err = filepath.Walk(sourceDir, func(path string, fi os.FileInfo, err error) error { // skip sourceDir @@ -62,17 +62,17 @@ func CreateTar(archiveInfos []*ArchiveInfo, w io.Writer) error { } if err != nil { - return fmt.Errorf("error accessing path %q: %w. Skipping.", path, err) + return errors.Wrapf(err, "error accessing path %q. Skipping.", path) } match := false for _, pattern := range ai.Paths { rel, err := filepath.Rel(sourceDir, path) if err != nil { - return err + return errors.WithStack(err) } ok, err := doublestar.Match(pattern, rel) if err != nil { - return err + return errors.WithStack(err) } if ok { match = true @@ -87,10 +87,10 @@ func CreateTar(archiveInfos []*ArchiveInfo, w io.Writer) error { // generate the path to save in the header destPath, err := archivePath(sourceDirInfo, sourceDir, destDir, path) if err != nil { - return err + return errors.WithStack(err) } if _, ok := seenDestPaths[destPath]; ok { - return fmt.Errorf("archive destination path %q already exists. Source path: %q", destPath, path) + return errors.Errorf("archive destination path %q already exists. Source path: %q", destPath, path) } seenDestPaths[destPath] = struct{}{} @@ -104,19 +104,19 @@ func CreateTar(archiveInfos []*ArchiveInfo, w io.Writer) error { var err error linkTarget, err = os.Readlink(path) if err != nil { - return fmt.Errorf("%s: readlink: %w", path, err) + return errors.Wrapf(err, "%s: readlink", path) } } hdr, err := tar.FileInfoHeader(fi, filepath.ToSlash(linkTarget)) if err != nil { - return fmt.Errorf("%s: making header: %w", path, err) + return errors.Wrapf(err, "%s: making header", path) } hdr.Name = destPath err = tw.WriteHeader(hdr) if err != nil { - return fmt.Errorf("%s: writing header: %w", hdr.Name, err) + return errors.Wrapf(err, "%s: writing header", hdr.Name) } if fi.IsDir() { @@ -126,18 +126,18 @@ func CreateTar(archiveInfos []*ArchiveInfo, w io.Writer) error { if fi.Mode().IsRegular() { f, err := os.Open(path) if err != nil { - return err + return errors.WithStack(err) } defer f.Close() if _, err := io.Copy(tw, f); err != nil { - return fmt.Errorf("%s: copying contents: %w", f.Name(), err) + return errors.Wrapf(err, "%s: copying contents", f.Name()) } } return nil }) if err != nil { - return fmt.Errorf("error walking the path %q: %w", sourceDir, err) + return errors.Wrapf(err, "error walking the path %q", sourceDir) } } @@ -151,16 +151,16 @@ func archivePath(sourceDirInfo os.FileInfo, sourceDir, baseDir, fpath string) (s var err error baseDir, err = filepath.Rel("/", baseDir) if err != nil { - return "", err + return "", errors.WithStack(err) } } if !sourceDirInfo.IsDir() { - return "", fmt.Errorf("sourceDir %q is not a directory", sourceDir) + return "", errors.Errorf("sourceDir %q is not a directory", sourceDir) } rel, err := filepath.Rel(sourceDir, fpath) if err != nil { - return "", err + return "", errors.WithStack(err) } return path.Join(baseDir, rel), nil } diff --git a/internal/toolbox/unarchive/unarchive.go b/internal/toolbox/unarchive/unarchive.go index 54f7ff5..b4df8ef 100644 --- a/internal/toolbox/unarchive/unarchive.go +++ b/internal/toolbox/unarchive/unarchive.go @@ -16,13 +16,13 @@ package unarchive import ( "archive/tar" - "errors" - "fmt" "io" "log" "os" "path/filepath" "runtime" + + "agola.io/agola/internal/errors" ) const ( @@ -33,19 +33,27 @@ func Unarchive(source io.Reader, destDir string, overwrite, removeDestDir bool) var err error destDir, err = filepath.Abs(destDir) if err != nil { - return fmt.Errorf("failed to calculate destination dir absolute path: %w", err) + return errors.Wrapf(err, "failed to calculate destination dir absolute path") } // don't follow destdir if it's a symlink fi, err := os.Lstat(destDir) if err != nil && !os.IsNotExist(err) { - return fmt.Errorf("failed to lstat destination dir: %w", err) + return errors.Wrapf(err, "failed to lstat destination dir") } if fi != nil && !fi.IsDir() { - return fmt.Errorf("destination path %q already exists and it's not a directory (mode: %q)", destDir, fi.Mode().String()) + return errors.Errorf( + "destination path %q already exists and it's not a directory (mode: %q)", + destDir, + fi.Mode().String(), + ) } if fi != nil && fi.IsDir() && removeDestDir { if err := os.RemoveAll(destDir); err != nil { - return fmt.Errorf("destination path %q already exists and it's not a directory (mode: %q)", destDir, fi.Mode().String()) + return errors.Errorf( + "destination path %q already exists and it's not a directory (mode: %q)", + destDir, + fi.Mode().String(), + ) } } @@ -57,7 +65,7 @@ func Unarchive(source io.Reader, destDir string, overwrite, removeDestDir bool) break } if err != nil { - return fmt.Errorf("error reading file in tar archive: %w", err) + return errors.Wrapf(err, "error reading file in tar archive") } } @@ -67,61 +75,61 @@ func Unarchive(source io.Reader, destDir string, overwrite, removeDestDir bool) func untarNext(tr *tar.Reader, destDir string, overwrite bool) error { hdr, err := tr.Next() if err != nil { - return err // don't wrap error; calling loop must break on io.EOF + return errors.WithStack(err) } destPath := filepath.Join(destDir, hdr.Name) log.Printf("file: %q", destPath) // do not overwrite existing files, if configured if !overwrite && fileExists(destPath) { - return fmt.Errorf("file already exists: %s", destPath) + return errors.Errorf("file already exists: %s", destPath) } // if "to" is a file and now exits and it's not a file then remove it if err := os.RemoveAll(destPath); err != nil { - return err + return errors.WithStack(err) } switch hdr.Typeflag { case tar.TypeDir: fi, err := os.Lstat(destPath) if err != nil && !os.IsNotExist(err) { - return err + return errors.WithStack(err) } if fi != nil && !fi.IsDir() { if err := os.RemoveAll(destPath); err != nil { - return err + return errors.WithStack(err) } } return mkdir(destPath, hdr.FileInfo().Mode()) case tar.TypeReg, tar.TypeRegA, tar.TypeChar, tar.TypeBlock, tar.TypeFifo: fi, err := os.Lstat(destPath) if err != nil && !os.IsNotExist(err) { - return err + return errors.WithStack(err) } if fi != nil && !fi.Mode().IsRegular() { if err := os.RemoveAll(destPath); err != nil { - return err + return errors.WithStack(err) } } return writeNewFile(destPath, tr, hdr.FileInfo().Mode()) case tar.TypeSymlink: if fileExists(destPath) { if err := os.RemoveAll(destPath); err != nil { - return err + return errors.WithStack(err) } } return writeNewSymbolicLink(destPath, hdr.Linkname) case tar.TypeLink: if fileExists(destPath) { if err := os.RemoveAll(destPath); err != nil { - return err + return errors.WithStack(err) } } return writeNewHardLink(destPath, filepath.Join(destPath, hdr.Linkname)) case tar.TypeXGlobalHeader: return nil // ignore the pax global header from git-generated tarballs default: - return fmt.Errorf("%s: unknown type flag: %c", hdr.Name, hdr.Typeflag) + return errors.Errorf("%s: unknown type flag: %c", hdr.Name, hdr.Typeflag) } } @@ -133,7 +141,7 @@ func fileExists(name string) bool { func mkdir(dirPath string, mode os.FileMode) error { err := os.MkdirAll(dirPath, mode) if err != nil { - return fmt.Errorf("%s: making directory: %w", dirPath, err) + return errors.Wrapf(err, "%s: making directory", dirPath) } return nil } @@ -141,23 +149,23 @@ func mkdir(dirPath string, mode os.FileMode) error { func writeNewFile(fpath string, in io.Reader, mode os.FileMode) error { err := os.MkdirAll(filepath.Dir(fpath), defaultDirPerm) if err != nil { - return fmt.Errorf("%s: making directory for file: %w", fpath, err) + return errors.Wrapf(err, "%s: making directory for file", fpath) } out, err := os.Create(fpath) if err != nil { - return fmt.Errorf("%s: creating new file: %w", fpath, err) + return errors.Wrapf(err, "%s: creating new file", fpath) } defer out.Close() err = out.Chmod(mode) if err != nil && runtime.GOOS != "windows" { - return fmt.Errorf("%s: changing file mode: %w", fpath, err) + return errors.Wrapf(err, "%s: changing file mode", fpath) } _, err = io.Copy(out, in) if err != nil { - return fmt.Errorf("%s: writing file: %w", fpath, err) + return errors.Wrapf(err, "%s: writing file", fpath) } return nil } @@ -165,11 +173,11 @@ func writeNewFile(fpath string, in io.Reader, mode os.FileMode) error { func writeNewSymbolicLink(fpath string, target string) error { err := os.MkdirAll(filepath.Dir(fpath), defaultDirPerm) if err != nil { - return fmt.Errorf("%s: making directory for file: %w", fpath, err) + return errors.Wrapf(err, "%s: making directory for file", fpath) } err = os.Symlink(target, fpath) if err != nil { - return fmt.Errorf("%s: making symbolic link for: %w", fpath, err) + return errors.Wrapf(err, "%s: making symbolic link for", fpath) } return nil } @@ -177,11 +185,11 @@ func writeNewSymbolicLink(fpath string, target string) error { func writeNewHardLink(fpath string, target string) error { err := os.MkdirAll(filepath.Dir(fpath), defaultDirPerm) if err != nil { - return fmt.Errorf("%s: making directory for file: %w", fpath, err) + return errors.Wrapf(err, "%s: making directory for file", fpath) } err = os.Link(target, fpath) if err != nil { - return fmt.Errorf("%s: making hard link for: %w", fpath, err) + return errors.Wrapf(err, "%s: making hard link for", fpath) } return nil } diff --git a/internal/util/backoff.go b/internal/util/backoff.go index 90e09d8..3c3f9b2 100644 --- a/internal/util/backoff.go +++ b/internal/util/backoff.go @@ -16,9 +16,10 @@ package util import ( "context" - "errors" "math/rand" "time" + + "agola.io/agola/internal/errors" ) // DefaultRetry is the recommended retry for a conflict where multiple clients @@ -105,7 +106,7 @@ func ExponentialBackoff(ctx context.Context, backoff Backoff, condition Conditio duration = time.Duration(float64(duration) * backoff.Factor) } if ok, err := condition(); err != nil || ok { - return err + return errors.WithStack(err) } } return ErrWaitTimeout diff --git a/internal/util/buffer.go b/internal/util/buffer.go index 2846695..c3d2467 100644 --- a/internal/util/buffer.go +++ b/internal/util/buffer.go @@ -17,6 +17,8 @@ package util import ( "bytes" "io" + + "agola.io/agola/internal/errors" ) type LimitedBuffer struct { @@ -24,11 +26,13 @@ type LimitedBuffer struct { cap int } -func (b *LimitedBuffer) Write(p []byte) (n int, err error) { +func (b *LimitedBuffer) Write(p []byte) (int, error) { if len(p)+b.Len() > b.cap { return 0, io.EOF } - return b.Buffer.Write(p) + n, err := b.Buffer.Write(p) + + return n, errors.WithStack(err) } func NewLimitedBuffer(cap int) *LimitedBuffer { diff --git a/internal/util/errors.go b/internal/util/errors.go index 948cda4..9864d23 100644 --- a/internal/util/errors.go +++ b/internal/util/errors.go @@ -15,9 +15,10 @@ package util import ( - "errors" "fmt" "strings" + + "agola.io/agola/internal/errors" ) // Errors is an error that contains multiple errors @@ -92,10 +93,12 @@ type APIError struct { Kind ErrorKind Code ErrorCode Message string + + *errors.Stack } func NewAPIError(kind ErrorKind, err error, options ...APIErrorOption) error { - derr := &APIError{err: err, Kind: kind} + derr := &APIError{err: err, Kind: kind, Stack: errors.Callers(0)} for _, opt := range options { opt(derr) diff --git a/internal/util/git.go b/internal/util/git.go index fee4f5f..463aa41 100644 --- a/internal/util/git.go +++ b/internal/util/git.go @@ -27,15 +27,15 @@ import ( "strings" "syscall" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/errors" ) // scpSyntaxRe matches the SCP-like addresses used by Git to access repositories // by SSH. var scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`) -func ParseGitURL(u string) (*url.URL, error) { - if m := scpSyntaxRe.FindStringSubmatch(u); m != nil { +func ParseGitURL(us string) (*url.URL, error) { + if m := scpSyntaxRe.FindStringSubmatch(us); m != nil { // Match SCP-like syntax and convert it to a URL. // Eg, "git@github.com:user/repo" becomes // "ssh://git@github.com/user/repo". @@ -46,7 +46,10 @@ func ParseGitURL(u string) (*url.URL, error) { Path: m[3], }, nil } - return url.Parse(u) + + u, err := url.Parse(us) + + return u, errors.WithStack(err) } type Git struct { @@ -86,17 +89,17 @@ func (g *Git) Output(ctx context.Context, stdin io.Reader, args ...string) ([]by if len(gitErr) > 0 { return nil, errors.New(stderr.String()) } else { - return nil, err + return nil, errors.WithStack(err) } } - return out, err + return out, errors.WithStack(err) } func (g *Git) OutputLines(ctx context.Context, stdin io.Reader, args ...string) ([]string, error) { out, err := g.Output(ctx, stdin, args...) if err != nil { - return nil, err + return nil, errors.WithStack(err) } scanner := bufio.NewScanner(bytes.NewReader(out)) @@ -105,7 +108,7 @@ func (g *Git) OutputLines(ctx context.Context, stdin io.Reader, args ...string) lines = append(lines, scanner.Text()) } if err := scanner.Err(); err != nil { - return nil, err + return nil, errors.WithStack(err) } return lines, nil } @@ -117,17 +120,17 @@ func (g *Git) Pipe(ctx context.Context, w io.Writer, r io.Reader, args ...string stdout, err := cmd.StdoutPipe() if err != nil { - return err + return errors.WithStack(err) } stderr := &bytes.Buffer{} cmd.Stderr = stderr if err := cmd.Start(); err != nil { - return err + return errors.WithStack(err) } if _, err := io.Copy(w, stdout); err != nil { - return err + return errors.WithStack(err) } if err := cmd.Wait(); err != nil { @@ -135,7 +138,7 @@ func (g *Git) Pipe(ctx context.Context, w io.Writer, r io.Reader, args ...string if len(gitErr) > 0 { return errors.New(stderr.String()) } else { - return err + return errors.WithStack(err) } } return nil @@ -162,7 +165,7 @@ func (g *Git) ConfigGet(ctx context.Context, args ...string) (string, error) { } } } - return "", err + return "", errors.WithStack(err) } return strings.TrimRight(string(out), "\000"), nil @@ -181,7 +184,7 @@ func (g *Git) ConfigSet(ctx context.Context, args ...string) (string, error) { } } } - return "", err + return "", errors.WithStack(err) } return strings.TrimRight(string(out), "\000"), nil diff --git a/internal/util/http.go b/internal/util/http.go index 8ec1421..13b4b45 100644 --- a/internal/util/http.go +++ b/internal/util/http.go @@ -6,7 +6,7 @@ import ( "io/ioutil" "net/http" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/errors" ) func HTTPResponse(w http.ResponseWriter, code int, res interface{}) error { @@ -16,11 +16,11 @@ func HTTPResponse(w http.ResponseWriter, code int, res interface{}) error { resj, err := json.Marshal(res) if err != nil { w.WriteHeader(http.StatusInternalServerError) - return err + return errors.WithStack(err) } w.WriteHeader(code) _, err = w.Write(resj) - return err + return errors.WithStack(err) } w.WriteHeader(code) @@ -96,7 +96,7 @@ func ErrFromRemote(resp *http.Response) error { data, err := ioutil.ReadAll(resp.Body) if err != nil { - return err + return errors.WithStack(err) } // Re-populate error response body so it can be parsed by the caller if needed diff --git a/internal/util/password.go b/internal/util/password.go index 34f7f0b..99f4352 100644 --- a/internal/util/password.go +++ b/internal/util/password.go @@ -15,14 +15,14 @@ package util import ( - "golang.org/x/crypto/bcrypt" + "agola.io/agola/internal/errors" - errors "golang.org/x/xerrors" + "golang.org/x/crypto/bcrypt" ) func PasswordHash(password string) (string, error) { passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - return string(passwordHash), err + return string(passwordHash), errors.WithStack(err) } func CompareHashAndPassword(passwordHash, password string) (bool, error) { @@ -30,7 +30,7 @@ func CompareHashAndPassword(passwordHash, password string) (bool, error) { if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) { return false, nil } - return false, err + return false, errors.WithStack(err) } return true, nil } diff --git a/internal/util/ssh.go b/internal/util/ssh.go index 2f8da5d..9c1ed46 100644 --- a/internal/util/ssh.go +++ b/internal/util/ssh.go @@ -20,8 +20,8 @@ import ( "crypto/rsa" "crypto/x509" "encoding/pem" - "errors" + "agola.io/agola/internal/errors" "golang.org/x/crypto/ssh" ) @@ -30,12 +30,12 @@ import ( func GenSSHKeyPair(bits int) ([]byte, []byte, error) { privateKey, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } err = privateKey.Validate() if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)} diff --git a/internal/util/string.go b/internal/util/string.go index 18e7c87..690406f 100644 --- a/internal/util/string.go +++ b/internal/util/string.go @@ -18,6 +18,8 @@ import ( "bufio" "io" "strings" + + "agola.io/agola/internal/errors" ) func CountLines(s string) (uint, error) { @@ -34,7 +36,7 @@ func CountLines(s string) (uint, error) { _, err := br.ReadBytes('\n') if err != nil { if err != io.EOF { - return 0, err + return 0, errors.WithStack(err) } stop = true } diff --git a/internal/util/tls.go b/internal/util/tls.go index e890b38..d9410c4 100644 --- a/internal/util/tls.go +++ b/internal/util/tls.go @@ -19,6 +19,8 @@ import ( "crypto/x509" "encoding/pem" "io/ioutil" + + "agola.io/agola/internal/errors" ) func NewTLSConfig(certFile, keyFile, caFile string, insecureSkipVerify bool) (*tls.Config, error) { @@ -28,7 +30,7 @@ func NewTLSConfig(certFile, keyFile, caFile string, insecureSkipVerify bool) (*t if caFile != "" { pemBytes, err := ioutil.ReadFile(caFile) if err != nil { - return nil, err + return nil, errors.WithStack(err) } roots := x509.NewCertPool() @@ -40,7 +42,7 @@ func NewTLSConfig(certFile, keyFile, caFile string, insecureSkipVerify bool) (*t } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { - return nil, err + return nil, errors.WithStack(err) } roots.AddCert(cert) } @@ -53,7 +55,7 @@ func NewTLSConfig(certFile, keyFile, caFile string, insecureSkipVerify bool) (*t if certFile != "" && keyFile != "" { cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { - return nil, err + return nil, errors.WithStack(err) } tlsConfig.Certificates = []tls.Certificate{cert} } diff --git a/internal/util/validation.go b/internal/util/validation.go index f32d14f..bcebd0f 100644 --- a/internal/util/validation.go +++ b/internal/util/validation.go @@ -15,9 +15,10 @@ package util import ( - "errors" "regexp" + "agola.io/agola/internal/errors" + "github.com/gofrs/uuid" ) diff --git a/services/configstore/client/client.go b/services/configstore/client/client.go index c3f6d98..d8a190a 100644 --- a/services/configstore/client/client.go +++ b/services/configstore/client/client.go @@ -25,6 +25,7 @@ import ( "strconv" "strings" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" csapitypes "agola.io/agola/services/configstore/api/types" cstypes "agola.io/agola/services/configstore/types" @@ -53,30 +54,32 @@ func (c *Client) SetHTTPClient(client *http.Client) { func (c *Client) doRequest(ctx context.Context, method, path string, query url.Values, header http.Header, ibody io.Reader) (*http.Response, error) { u, err := url.Parse(c.url + "/api/v1alpha" + path) if err != nil { - return nil, err + return nil, errors.WithStack(err) } u.RawQuery = query.Encode() req, err := http.NewRequest(method, u.String(), ibody) req = req.WithContext(ctx) if err != nil { - return nil, err + return nil, errors.WithStack(err) } for k, v := range header { req.Header[k] = v } - return c.client.Do(req) + res, err := c.client.Do(req) + + return res, errors.WithStack(err) } func (c *Client) getResponse(ctx context.Context, method, path string, query url.Values, header http.Header, ibody io.Reader) (*http.Response, error) { resp, err := c.doRequest(ctx, method, path, query, header, ibody) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := util.ErrFromRemote(resp); err != nil { - return resp, err + return resp, errors.WithStack(err) } return resp, nil @@ -85,53 +88,53 @@ func (c *Client) getResponse(ctx context.Context, method, path string, query url func (c *Client) getParsedResponse(ctx context.Context, method, path string, query url.Values, header http.Header, ibody io.Reader, obj interface{}) (*http.Response, error) { resp, err := c.getResponse(ctx, method, path, query, header, ibody) if err != nil { - return resp, err + return resp, errors.WithStack(err) } defer resp.Body.Close() d := json.NewDecoder(resp.Body) - return resp, d.Decode(obj) + return resp, errors.WithStack(d.Decode(obj)) } func (c *Client) GetProjectGroup(ctx context.Context, projectGroupRef string) (*csapitypes.ProjectGroup, *http.Response, error) { projectGroup := new(csapitypes.ProjectGroup) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s", url.PathEscape(projectGroupRef)), nil, jsonContent, nil, projectGroup) - return projectGroup, resp, err + return projectGroup, resp, errors.WithStack(err) } func (c *Client) GetProjectGroupSubgroups(ctx context.Context, projectGroupRef string) ([]*csapitypes.ProjectGroup, *http.Response, error) { projectGroups := []*csapitypes.ProjectGroup{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s/subgroups", url.PathEscape(projectGroupRef)), nil, jsonContent, nil, &projectGroups) - return projectGroups, resp, err + return projectGroups, resp, errors.WithStack(err) } func (c *Client) GetProjectGroupProjects(ctx context.Context, projectGroupRef string) ([]*csapitypes.Project, *http.Response, error) { projects := []*csapitypes.Project{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s/projects", url.PathEscape(projectGroupRef)), nil, jsonContent, nil, &projects) - return projects, resp, err + return projects, resp, errors.WithStack(err) } func (c *Client) CreateProjectGroup(ctx context.Context, projectGroup *cstypes.ProjectGroup) (*csapitypes.ProjectGroup, *http.Response, error) { pj, err := json.Marshal(projectGroup) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resProjectGroup := new(csapitypes.ProjectGroup) resp, err := c.getParsedResponse(ctx, "POST", "/projectgroups", nil, jsonContent, bytes.NewReader(pj), resProjectGroup) - return resProjectGroup, resp, err + return resProjectGroup, resp, errors.WithStack(err) } func (c *Client) UpdateProjectGroup(ctx context.Context, projectGroupRef string, projectGroup *cstypes.ProjectGroup) (*csapitypes.ProjectGroup, *http.Response, error) { pj, err := json.Marshal(projectGroup) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resProjectGroup := new(csapitypes.ProjectGroup) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/projectgroups/%s", url.PathEscape(projectGroupRef)), nil, jsonContent, bytes.NewReader(pj), resProjectGroup) - return resProjectGroup, resp, err + return resProjectGroup, resp, errors.WithStack(err) } func (c *Client) DeleteProjectGroup(ctx context.Context, projectGroupRef string) (*http.Response, error) { @@ -141,29 +144,29 @@ func (c *Client) DeleteProjectGroup(ctx context.Context, projectGroupRef string) func (c *Client) GetProject(ctx context.Context, projectRef string) (*csapitypes.Project, *http.Response, error) { project := new(csapitypes.Project) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projects/%s", url.PathEscape(projectRef)), nil, jsonContent, nil, project) - return project, resp, err + return project, resp, errors.WithStack(err) } func (c *Client) CreateProject(ctx context.Context, project *cstypes.Project) (*csapitypes.Project, *http.Response, error) { pj, err := json.Marshal(project) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resProject := new(csapitypes.Project) resp, err := c.getParsedResponse(ctx, "POST", "/projects", nil, jsonContent, bytes.NewReader(pj), resProject) - return resProject, resp, err + return resProject, resp, errors.WithStack(err) } func (c *Client) UpdateProject(ctx context.Context, projectRef string, project *cstypes.Project) (*csapitypes.Project, *http.Response, error) { pj, err := json.Marshal(project) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resProject := new(csapitypes.Project) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/projects/%s", url.PathEscape(projectRef)), nil, jsonContent, bytes.NewReader(pj), resProject) - return resProject, resp, err + return resProject, resp, errors.WithStack(err) } func (c *Client) DeleteProject(ctx context.Context, projectRef string) (*http.Response, error) { @@ -178,7 +181,7 @@ func (c *Client) GetProjectGroupSecrets(ctx context.Context, projectGroupRef str secrets := []*csapitypes.Secret{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s/secrets", url.PathEscape(projectGroupRef)), q, jsonContent, nil, &secrets) - return secrets, resp, err + return secrets, resp, errors.WithStack(err) } func (c *Client) GetProjectSecrets(ctx context.Context, projectRef string, tree bool) ([]*csapitypes.Secret, *http.Response, error) { @@ -189,51 +192,51 @@ func (c *Client) GetProjectSecrets(ctx context.Context, projectRef string, tree secrets := []*csapitypes.Secret{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projects/%s/secrets", url.PathEscape(projectRef)), q, jsonContent, nil, &secrets) - return secrets, resp, err + return secrets, resp, errors.WithStack(err) } func (c *Client) CreateProjectGroupSecret(ctx context.Context, projectGroupRef string, secret *cstypes.Secret) (*csapitypes.Secret, *http.Response, error) { pj, err := json.Marshal(secret) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resSecret := new(csapitypes.Secret) resp, err := c.getParsedResponse(ctx, "POST", fmt.Sprintf("/projectgroups/%s/secrets", url.PathEscape(projectGroupRef)), nil, jsonContent, bytes.NewReader(pj), resSecret) - return resSecret, resp, err + return resSecret, resp, errors.WithStack(err) } func (c *Client) CreateProjectSecret(ctx context.Context, projectRef string, secret *cstypes.Secret) (*csapitypes.Secret, *http.Response, error) { pj, err := json.Marshal(secret) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resSecret := new(csapitypes.Secret) resp, err := c.getParsedResponse(ctx, "POST", fmt.Sprintf("/projects/%s/secrets", url.PathEscape(projectRef)), nil, jsonContent, bytes.NewReader(pj), resSecret) - return resSecret, resp, err + return resSecret, resp, errors.WithStack(err) } func (c *Client) UpdateProjectGroupSecret(ctx context.Context, projectGroupRef, secretName string, secret *cstypes.Secret) (*csapitypes.Secret, *http.Response, error) { pj, err := json.Marshal(secret) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resSecret := new(csapitypes.Secret) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/projectgroups/%s/secrets/%s", url.PathEscape(projectGroupRef), secretName), nil, jsonContent, bytes.NewReader(pj), resSecret) - return resSecret, resp, err + return resSecret, resp, errors.WithStack(err) } func (c *Client) UpdateProjectSecret(ctx context.Context, projectRef, secretName string, secret *cstypes.Secret) (*csapitypes.Secret, *http.Response, error) { pj, err := json.Marshal(secret) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resSecret := new(csapitypes.Secret) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/projects/%s/secrets/%s", url.PathEscape(projectRef), secretName), nil, jsonContent, bytes.NewReader(pj), resSecret) - return resSecret, resp, err + return resSecret, resp, errors.WithStack(err) } func (c *Client) DeleteProjectGroupSecret(ctx context.Context, projectGroupRef, secretName string) (*http.Response, error) { @@ -252,7 +255,7 @@ func (c *Client) GetProjectGroupVariables(ctx context.Context, projectGroupRef s variables := []*csapitypes.Variable{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s/variables", url.PathEscape(projectGroupRef)), q, jsonContent, nil, &variables) - return variables, resp, err + return variables, resp, errors.WithStack(err) } func (c *Client) GetProjectVariables(ctx context.Context, projectRef string, tree bool) ([]*csapitypes.Variable, *http.Response, error) { @@ -263,51 +266,51 @@ func (c *Client) GetProjectVariables(ctx context.Context, projectRef string, tre variables := []*csapitypes.Variable{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projects/%s/variables", url.PathEscape(projectRef)), q, jsonContent, nil, &variables) - return variables, resp, err + return variables, resp, errors.WithStack(err) } func (c *Client) CreateProjectGroupVariable(ctx context.Context, projectGroupRef string, variable *cstypes.Variable) (*csapitypes.Variable, *http.Response, error) { pj, err := json.Marshal(variable) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resVariable := new(csapitypes.Variable) resp, err := c.getParsedResponse(ctx, "POST", fmt.Sprintf("/projectgroups/%s/variables", url.PathEscape(projectGroupRef)), nil, jsonContent, bytes.NewReader(pj), resVariable) - return resVariable, resp, err + return resVariable, resp, errors.WithStack(err) } func (c *Client) UpdateProjectGroupVariable(ctx context.Context, projectGroupRef, variableName string, variable *cstypes.Variable) (*csapitypes.Variable, *http.Response, error) { pj, err := json.Marshal(variable) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resVariable := new(csapitypes.Variable) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/projectgroups/%s/variables/%s", url.PathEscape(projectGroupRef), variableName), nil, jsonContent, bytes.NewReader(pj), resVariable) - return resVariable, resp, err + return resVariable, resp, errors.WithStack(err) } func (c *Client) CreateProjectVariable(ctx context.Context, projectRef string, variable *cstypes.Variable) (*csapitypes.Variable, *http.Response, error) { pj, err := json.Marshal(variable) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resVariable := new(csapitypes.Variable) resp, err := c.getParsedResponse(ctx, "POST", fmt.Sprintf("/projects/%s/variables", url.PathEscape(projectRef)), nil, jsonContent, bytes.NewReader(pj), resVariable) - return resVariable, resp, err + return resVariable, resp, errors.WithStack(err) } func (c *Client) UpdateProjectVariable(ctx context.Context, projectRef, variableName string, variable *cstypes.Variable) (*csapitypes.Variable, *http.Response, error) { pj, err := json.Marshal(variable) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resVariable := new(csapitypes.Variable) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/projects/%s/variables/%s", url.PathEscape(projectRef), variableName), nil, jsonContent, bytes.NewReader(pj), resVariable) - return resVariable, resp, err + return resVariable, resp, errors.WithStack(err) } func (c *Client) DeleteProjectGroupVariable(ctx context.Context, projectGroupRef, variableName string) (*http.Response, error) { @@ -321,7 +324,7 @@ func (c *Client) DeleteProjectVariable(ctx context.Context, projectRef, variable func (c *Client) GetUser(ctx context.Context, userRef string) (*cstypes.User, *http.Response, error) { user := new(cstypes.User) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/users/%s", userRef), nil, jsonContent, nil, user) - return user, resp, err + return user, resp, errors.WithStack(err) } func (c *Client) GetUserByToken(ctx context.Context, token string) (*cstypes.User, *http.Response, error) { @@ -332,9 +335,9 @@ func (c *Client) GetUserByToken(ctx context.Context, token string) (*cstypes.Use users := []*cstypes.User{} resp, err := c.getParsedResponse(ctx, "GET", "/users", q, jsonContent, nil, &users) if err != nil { - return nil, resp, err + return nil, resp, errors.WithStack(err) } - return users[0], resp, err + return users[0], resp, errors.WithStack(err) } func (c *Client) GetUserByLinkedAccountRemoteUserAndSource(ctx context.Context, remoteUserID, remoteSourceID string) (*cstypes.User, *http.Response, error) { @@ -346,9 +349,9 @@ func (c *Client) GetUserByLinkedAccountRemoteUserAndSource(ctx context.Context, users := []*cstypes.User{} resp, err := c.getParsedResponse(ctx, "GET", "/users", q, jsonContent, nil, &users) if err != nil { - return nil, resp, err + return nil, resp, errors.WithStack(err) } - return users[0], resp, err + return users[0], resp, errors.WithStack(err) } func (c *Client) GetUserByLinkedAccount(ctx context.Context, linkedAccountID string) (*cstypes.User, *http.Response, error) { @@ -359,31 +362,31 @@ func (c *Client) GetUserByLinkedAccount(ctx context.Context, linkedAccountID str users := []*cstypes.User{} resp, err := c.getParsedResponse(ctx, "GET", "/users", q, jsonContent, nil, &users) if err != nil { - return nil, resp, err + return nil, resp, errors.WithStack(err) } - return users[0], resp, err + return users[0], resp, errors.WithStack(err) } func (c *Client) CreateUser(ctx context.Context, req *csapitypes.CreateUserRequest) (*cstypes.User, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } user := new(cstypes.User) resp, err := c.getParsedResponse(ctx, "POST", "/users", nil, jsonContent, bytes.NewReader(reqj), user) - return user, resp, err + return user, resp, errors.WithStack(err) } func (c *Client) UpdateUser(ctx context.Context, userRef string, req *csapitypes.UpdateUserRequest) (*cstypes.User, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } user := new(cstypes.User) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/users/%s", userRef), nil, jsonContent, bytes.NewReader(reqj), user) - return user, resp, err + return user, resp, errors.WithStack(err) } func (c *Client) DeleteUser(ctx context.Context, userRef string) (*http.Response, error) { @@ -404,18 +407,18 @@ func (c *Client) GetUsers(ctx context.Context, start string, limit int, asc bool users := []*cstypes.User{} resp, err := c.getParsedResponse(ctx, "GET", "/users", q, jsonContent, nil, &users) - return users, resp, err + return users, resp, errors.WithStack(err) } func (c *Client) CreateUserLA(ctx context.Context, userRef string, req *csapitypes.CreateUserLARequest) (*cstypes.LinkedAccount, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } la := new(cstypes.LinkedAccount) resp, err := c.getParsedResponse(ctx, "POST", fmt.Sprintf("/users/%s/linkedaccounts", userRef), nil, jsonContent, bytes.NewReader(reqj), la) - return la, resp, err + return la, resp, errors.WithStack(err) } func (c *Client) DeleteUserLA(ctx context.Context, userRef, laID string) (*http.Response, error) { @@ -425,23 +428,23 @@ func (c *Client) DeleteUserLA(ctx context.Context, userRef, laID string) (*http. func (c *Client) UpdateUserLA(ctx context.Context, userRef, laID string, req *csapitypes.UpdateUserLARequest) (*cstypes.LinkedAccount, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } la := new(cstypes.LinkedAccount) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/users/%s/linkedaccounts/%s", userRef, laID), nil, jsonContent, bytes.NewReader(reqj), la) - return la, resp, err + return la, resp, errors.WithStack(err) } func (c *Client) CreateUserToken(ctx context.Context, userRef string, req *csapitypes.CreateUserTokenRequest) (*csapitypes.CreateUserTokenResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } tresp := new(csapitypes.CreateUserTokenResponse) resp, err := c.getParsedResponse(ctx, "POST", fmt.Sprintf("/users/%s/tokens", userRef), nil, jsonContent, bytes.NewReader(reqj), tresp) - return tresp, resp, err + return tresp, resp, errors.WithStack(err) } func (c *Client) DeleteUserToken(ctx context.Context, userRef, tokenName string) (*http.Response, error) { @@ -451,13 +454,13 @@ func (c *Client) DeleteUserToken(ctx context.Context, userRef, tokenName string) func (c *Client) GetUserOrgs(ctx context.Context, userRef string) ([]*csapitypes.UserOrgsResponse, *http.Response, error) { userOrgs := []*csapitypes.UserOrgsResponse{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/users/%s/orgs", userRef), nil, jsonContent, nil, &userOrgs) - return userOrgs, resp, err + return userOrgs, resp, errors.WithStack(err) } func (c *Client) GetRemoteSource(ctx context.Context, rsRef string) (*cstypes.RemoteSource, *http.Response, error) { rs := new(cstypes.RemoteSource) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/remotesources/%s", rsRef), nil, jsonContent, nil, rs) - return rs, resp, err + return rs, resp, errors.WithStack(err) } func (c *Client) GetRemoteSources(ctx context.Context, start string, limit int, asc bool) ([]*cstypes.RemoteSource, *http.Response, error) { @@ -474,29 +477,29 @@ func (c *Client) GetRemoteSources(ctx context.Context, start string, limit int, rss := []*cstypes.RemoteSource{} resp, err := c.getParsedResponse(ctx, "GET", "/remotesources", q, jsonContent, nil, &rss) - return rss, resp, err + return rss, resp, errors.WithStack(err) } func (c *Client) CreateRemoteSource(ctx context.Context, rs *cstypes.RemoteSource) (*cstypes.RemoteSource, *http.Response, error) { rsj, err := json.Marshal(rs) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } rs = new(cstypes.RemoteSource) resp, err := c.getParsedResponse(ctx, "POST", "/remotesources", nil, jsonContent, bytes.NewReader(rsj), rs) - return rs, resp, err + return rs, resp, errors.WithStack(err) } func (c *Client) UpdateRemoteSource(ctx context.Context, remoteSourceRef string, remoteSource *cstypes.RemoteSource) (*cstypes.RemoteSource, *http.Response, error) { rsj, err := json.Marshal(remoteSource) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } resRemoteSource := new(cstypes.RemoteSource) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/remotesources/%s", url.PathEscape(remoteSourceRef)), nil, jsonContent, bytes.NewReader(rsj), resRemoteSource) - return resRemoteSource, resp, err + return resRemoteSource, resp, errors.WithStack(err) } func (c *Client) DeleteRemoteSource(ctx context.Context, rsRef string) (*http.Response, error) { @@ -506,12 +509,12 @@ func (c *Client) DeleteRemoteSource(ctx context.Context, rsRef string) (*http.Re func (c *Client) CreateOrg(ctx context.Context, org *cstypes.Organization) (*cstypes.Organization, *http.Response, error) { oj, err := json.Marshal(org) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } org = new(cstypes.Organization) resp, err := c.getParsedResponse(ctx, "POST", "/orgs", nil, jsonContent, bytes.NewReader(oj), org) - return org, resp, err + return org, resp, errors.WithStack(err) } func (c *Client) DeleteOrg(ctx context.Context, orgRef string) (*http.Response, error) { @@ -524,12 +527,12 @@ func (c *Client) AddOrgMember(ctx context.Context, orgRef, userRef string, role } omj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } orgmember := new(cstypes.OrganizationMember) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/orgs/%s/members/%s", orgRef, userRef), nil, jsonContent, bytes.NewReader(omj), orgmember) - return orgmember, resp, err + return orgmember, resp, errors.WithStack(err) } func (c *Client) RemoveOrgMember(ctx context.Context, orgRef, userRef string) (*http.Response, error) { @@ -550,17 +553,17 @@ func (c *Client) GetOrgs(ctx context.Context, start string, limit int, asc bool) orgs := []*cstypes.Organization{} resp, err := c.getParsedResponse(ctx, "GET", "/orgs", q, jsonContent, nil, &orgs) - return orgs, resp, err + return orgs, resp, errors.WithStack(err) } func (c *Client) GetOrg(ctx context.Context, orgRef string) (*cstypes.Organization, *http.Response, error) { org := new(cstypes.Organization) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/orgs/%s", orgRef), nil, jsonContent, nil, org) - return org, resp, err + return org, resp, errors.WithStack(err) } func (c *Client) GetOrgMembers(ctx context.Context, orgRef string) ([]*csapitypes.OrgMemberResponse, *http.Response, error) { orgMembers := []*csapitypes.OrgMemberResponse{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/orgs/%s/members", orgRef), nil, jsonContent, nil, &orgMembers) - return orgMembers, resp, err + return orgMembers, resp, errors.WithStack(err) } diff --git a/services/configstore/types/types.go b/services/configstore/types/types.go index dd1c937..827cd52 100644 --- a/services/configstore/types/types.go +++ b/services/configstore/types/types.go @@ -16,9 +16,9 @@ package types import ( "encoding/json" - "fmt" "time" + "agola.io/agola/internal/errors" "agola.io/agola/services/types" "agola.io/agola/util" ) @@ -189,7 +189,7 @@ func (rs *RemoteSource) UnmarshalJSON(b []byte) error { trs := (*remoteSource)(rs) if err := json.Unmarshal(b, &trs); err != nil { - return err + return errors.WithStack(err) } if trs.RegistrationEnabled == nil { @@ -212,7 +212,7 @@ func SourceSupportedAuthTypes(rsType RemoteSourceType) []RemoteSourceAuthType { return []RemoteSourceAuthType{RemoteSourceAuthTypeOauth2} default: - panic(fmt.Errorf("unsupported remote source type: %q", rsType)) + panic(errors.Errorf("unsupported remote source type: %q", rsType)) } } diff --git a/services/gateway/client/client.go b/services/gateway/client/client.go index eed6c2e..c9ed913 100644 --- a/services/gateway/client/client.go +++ b/services/gateway/client/client.go @@ -26,6 +26,7 @@ import ( "strconv" "strings" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" gwapitypes "agola.io/agola/services/gateway/api/types" ) @@ -55,13 +56,13 @@ func (c *Client) SetHTTPClient(client *http.Client) { func (c *Client) doRequest(ctx context.Context, method, path string, query url.Values, header http.Header, ibody io.Reader) (*http.Response, error) { u, err := url.Parse(c.url + "/api/v1alpha" + path) if err != nil { - return nil, err + return nil, errors.WithStack(err) } u.RawQuery = query.Encode() req, err := http.NewRequest(method, u.String(), ibody) req = req.WithContext(ctx) if err != nil { - return nil, err + return nil, errors.WithStack(err) } req.Header.Set("Authorization", "token "+c.token) @@ -69,17 +70,19 @@ func (c *Client) doRequest(ctx context.Context, method, path string, query url.V req.Header[k] = v } - return c.client.Do(req) + res, err := c.client.Do(req) + + return res, errors.WithStack(err) } func (c *Client) getResponse(ctx context.Context, method, path string, query url.Values, header http.Header, ibody io.Reader) (*http.Response, error) { resp, err := c.doRequest(ctx, method, path, query, header, ibody) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := util.ErrFromRemote(resp); err != nil { - return resp, err + return resp, errors.WithStack(err) } return resp, nil @@ -88,59 +91,59 @@ func (c *Client) getResponse(ctx context.Context, method, path string, query url func (c *Client) getParsedResponse(ctx context.Context, method, path string, query url.Values, header http.Header, ibody io.Reader, obj interface{}) (*http.Response, error) { resp, err := c.getResponse(ctx, method, path, query, header, ibody) if err != nil { - return resp, err + return resp, errors.WithStack(err) } defer resp.Body.Close() d := json.NewDecoder(resp.Body) - return resp, d.Decode(obj) + return resp, errors.WithStack(d.Decode(obj)) } func (c *Client) GetProjectGroup(ctx context.Context, projectGroupRef string) (*gwapitypes.ProjectGroupResponse, *http.Response, error) { projectGroup := new(gwapitypes.ProjectGroupResponse) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s", url.PathEscape(projectGroupRef)), nil, jsonContent, nil, projectGroup) - return projectGroup, resp, err + return projectGroup, resp, errors.WithStack(err) } func (c *Client) GetProjectGroupSubgroups(ctx context.Context, projectGroupRef string) ([]*gwapitypes.ProjectGroupResponse, *http.Response, error) { projectGroups := []*gwapitypes.ProjectGroupResponse{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s/subgroups", url.PathEscape(projectGroupRef)), nil, jsonContent, nil, &projectGroups) - return projectGroups, resp, err + return projectGroups, resp, errors.WithStack(err) } func (c *Client) GetProjectGroupProjects(ctx context.Context, projectGroupRef string) ([]*gwapitypes.ProjectResponse, *http.Response, error) { projects := []*gwapitypes.ProjectResponse{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s/projects", url.PathEscape(projectGroupRef)), nil, jsonContent, nil, &projects) - return projects, resp, err + return projects, resp, errors.WithStack(err) } func (c *Client) GetProject(ctx context.Context, projectRef string) (*gwapitypes.ProjectResponse, *http.Response, error) { project := new(gwapitypes.ProjectResponse) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projects/%s", url.PathEscape(projectRef)), nil, jsonContent, nil, project) - return project, resp, err + return project, resp, errors.WithStack(err) } func (c *Client) CreateProjectGroup(ctx context.Context, req *gwapitypes.CreateProjectGroupRequest) (*gwapitypes.ProjectResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } projectGroup := new(gwapitypes.ProjectResponse) resp, err := c.getParsedResponse(ctx, "POST", "/projectgroups", nil, jsonContent, bytes.NewReader(reqj), projectGroup) - return projectGroup, resp, err + return projectGroup, resp, errors.WithStack(err) } func (c *Client) UpdateProjectGroup(ctx context.Context, projectGroupRef string, req *gwapitypes.UpdateProjectGroupRequest) (*gwapitypes.ProjectResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } projectGroup := new(gwapitypes.ProjectResponse) resp, err := c.getParsedResponse(ctx, "PUT", path.Join("/projectgroups", url.PathEscape(projectGroupRef)), nil, jsonContent, bytes.NewReader(reqj), projectGroup) - return projectGroup, resp, err + return projectGroup, resp, errors.WithStack(err) } func (c *Client) DeleteProjectGroup(ctx context.Context, projectGroupRef string) (*http.Response, error) { @@ -150,45 +153,45 @@ func (c *Client) DeleteProjectGroup(ctx context.Context, projectGroupRef string) func (c *Client) CreateProject(ctx context.Context, req *gwapitypes.CreateProjectRequest) (*gwapitypes.ProjectResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } project := new(gwapitypes.ProjectResponse) resp, err := c.getParsedResponse(ctx, "POST", "/projects", nil, jsonContent, bytes.NewReader(reqj), project) - return project, resp, err + return project, resp, errors.WithStack(err) } func (c *Client) UpdateProject(ctx context.Context, projectRef string, req *gwapitypes.UpdateProjectRequest) (*gwapitypes.ProjectResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } project := new(gwapitypes.ProjectResponse) resp, err := c.getParsedResponse(ctx, "PUT", path.Join("/projects", url.PathEscape(projectRef)), nil, jsonContent, bytes.NewReader(reqj), project) - return project, resp, err + return project, resp, errors.WithStack(err) } func (c *Client) CreateProjectGroupSecret(ctx context.Context, projectGroupRef string, req *gwapitypes.CreateSecretRequest) (*gwapitypes.SecretResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } secret := new(gwapitypes.SecretResponse) resp, err := c.getParsedResponse(ctx, "POST", path.Join("/projectgroups", url.PathEscape(projectGroupRef), "secrets"), nil, jsonContent, bytes.NewReader(reqj), secret) - return secret, resp, err + return secret, resp, errors.WithStack(err) } func (c *Client) UpdateProjectGroupSecret(ctx context.Context, projectGroupRef, secretName string, req *gwapitypes.UpdateSecretRequest) (*gwapitypes.SecretResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } secret := new(gwapitypes.SecretResponse) resp, err := c.getParsedResponse(ctx, "PUT", path.Join("/projectgroups", url.PathEscape(projectGroupRef), "secrets", secretName), nil, jsonContent, bytes.NewReader(reqj), secret) - return secret, resp, err + return secret, resp, errors.WithStack(err) } func (c *Client) DeleteProjectGroupSecret(ctx context.Context, projectGroupRef, secretName string) (*http.Response, error) { @@ -205,29 +208,29 @@ func (c *Client) GetProjectGroupSecrets(ctx context.Context, projectRef string, q.Add("removeoverridden", "") } resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s/secrets", url.PathEscape(projectRef)), q, jsonContent, nil, &secrets) - return secrets, resp, err + return secrets, resp, errors.WithStack(err) } func (c *Client) CreateProjectSecret(ctx context.Context, projectRef string, req *gwapitypes.CreateSecretRequest) (*gwapitypes.SecretResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } secret := new(gwapitypes.SecretResponse) resp, err := c.getParsedResponse(ctx, "POST", path.Join("/projects", url.PathEscape(projectRef), "secrets"), nil, jsonContent, bytes.NewReader(reqj), secret) - return secret, resp, err + return secret, resp, errors.WithStack(err) } func (c *Client) UpdateProjectSecret(ctx context.Context, projectRef, secretName string, req *gwapitypes.UpdateSecretRequest) (*gwapitypes.SecretResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } secret := new(gwapitypes.SecretResponse) resp, err := c.getParsedResponse(ctx, "PUT", path.Join("/projects", url.PathEscape(projectRef), "secrets", secretName), nil, jsonContent, bytes.NewReader(reqj), secret) - return secret, resp, err + return secret, resp, errors.WithStack(err) } func (c *Client) DeleteProjectSecret(ctx context.Context, projectRef, secretName string) (*http.Response, error) { @@ -244,29 +247,29 @@ func (c *Client) GetProjectSecrets(ctx context.Context, projectRef string, tree, q.Add("removeoverridden", "") } resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projects/%s/secrets", url.PathEscape(projectRef)), q, jsonContent, nil, &secrets) - return secrets, resp, err + return secrets, resp, errors.WithStack(err) } func (c *Client) CreateProjectGroupVariable(ctx context.Context, projectGroupRef string, req *gwapitypes.CreateVariableRequest) (*gwapitypes.VariableResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } variable := new(gwapitypes.VariableResponse) resp, err := c.getParsedResponse(ctx, "POST", path.Join("/projectgroups", url.PathEscape(projectGroupRef), "variables"), nil, jsonContent, bytes.NewReader(reqj), variable) - return variable, resp, err + return variable, resp, errors.WithStack(err) } func (c *Client) UpdateProjectGroupVariable(ctx context.Context, projectGroupRef, variableName string, req *gwapitypes.UpdateVariableRequest) (*gwapitypes.VariableResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } variable := new(gwapitypes.VariableResponse) resp, err := c.getParsedResponse(ctx, "PUT", path.Join("/projectgroups", url.PathEscape(projectGroupRef), "variables", variableName), nil, jsonContent, bytes.NewReader(reqj), variable) - return variable, resp, err + return variable, resp, errors.WithStack(err) } func (c *Client) DeleteProjectGroupVariable(ctx context.Context, projectGroupRef, variableName string) (*http.Response, error) { @@ -283,29 +286,29 @@ func (c *Client) GetProjectGroupVariables(ctx context.Context, projectRef string q.Add("removeoverridden", "") } resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projectgroups/%s/variables", url.PathEscape(projectRef)), q, jsonContent, nil, &variables) - return variables, resp, err + return variables, resp, errors.WithStack(err) } func (c *Client) CreateProjectVariable(ctx context.Context, projectRef string, req *gwapitypes.CreateVariableRequest) (*gwapitypes.VariableResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } variable := new(gwapitypes.VariableResponse) resp, err := c.getParsedResponse(ctx, "POST", path.Join("/projects", url.PathEscape(projectRef), "variables"), nil, jsonContent, bytes.NewReader(reqj), variable) - return variable, resp, err + return variable, resp, errors.WithStack(err) } func (c *Client) UpdateProjectVariable(ctx context.Context, projectRef, variableName string, req *gwapitypes.UpdateVariableRequest) (*gwapitypes.VariableResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } variable := new(gwapitypes.VariableResponse) resp, err := c.getParsedResponse(ctx, "PUT", path.Join("/projects", url.PathEscape(projectRef), "variables", variableName), nil, jsonContent, bytes.NewReader(reqj), variable) - return variable, resp, err + return variable, resp, errors.WithStack(err) } func (c *Client) DeleteProjectVariable(ctx context.Context, projectRef, variableName string) (*http.Response, error) { @@ -322,7 +325,7 @@ func (c *Client) GetProjectVariables(ctx context.Context, projectRef string, tre q.Add("removeoverridden", "") } resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projects/%s/variables", url.PathEscape(projectRef)), q, jsonContent, nil, &variables) - return variables, resp, err + return variables, resp, errors.WithStack(err) } func (c *Client) DeleteProject(ctx context.Context, projectRef string) (*http.Response, error) { @@ -332,7 +335,7 @@ func (c *Client) DeleteProject(ctx context.Context, projectRef string) (*http.Re func (c *Client) ProjectCreateRun(ctx context.Context, projectRef string, req *gwapitypes.ProjectCreateRunRequest) (*http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return c.getResponse(ctx, "POST", fmt.Sprintf("/projects/%s/createrun", url.PathEscape(projectRef)), nil, jsonContent, bytes.NewReader(reqj)) @@ -345,13 +348,13 @@ func (c *Client) ReconfigProject(ctx context.Context, projectRef string) (*http. func (c *Client) GetCurrentUser(ctx context.Context) (*gwapitypes.UserResponse, *http.Response, error) { user := new(gwapitypes.UserResponse) resp, err := c.getParsedResponse(ctx, "GET", "/user", nil, jsonContent, nil, user) - return user, resp, err + return user, resp, errors.WithStack(err) } func (c *Client) GetUser(ctx context.Context, userRef string) (*gwapitypes.UserResponse, *http.Response, error) { user := new(gwapitypes.UserResponse) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/users/%s", userRef), nil, jsonContent, nil, user) - return user, resp, err + return user, resp, errors.WithStack(err) } func (c *Client) GetUsers(ctx context.Context, start string, limit int, asc bool) ([]*gwapitypes.UserResponse, *http.Response, error) { @@ -368,18 +371,18 @@ func (c *Client) GetUsers(ctx context.Context, start string, limit int, asc bool users := []*gwapitypes.UserResponse{} resp, err := c.getParsedResponse(ctx, "GET", "/users", q, jsonContent, nil, &users) - return users, resp, err + return users, resp, errors.WithStack(err) } func (c *Client) CreateUser(ctx context.Context, req *gwapitypes.CreateUserRequest) (*gwapitypes.UserResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } user := new(gwapitypes.UserResponse) resp, err := c.getParsedResponse(ctx, "POST", "/users", nil, jsonContent, bytes.NewReader(reqj), user) - return user, resp, err + return user, resp, errors.WithStack(err) } func (c *Client) DeleteUser(ctx context.Context, userRef string) (*http.Response, error) { @@ -389,7 +392,7 @@ func (c *Client) DeleteUser(ctx context.Context, userRef string) (*http.Response func (c *Client) UserCreateRun(ctx context.Context, req *gwapitypes.UserCreateRunRequest) (*http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return c.getResponse(ctx, "POST", "/user/createrun", nil, jsonContent, bytes.NewReader(reqj)) @@ -398,12 +401,12 @@ func (c *Client) UserCreateRun(ctx context.Context, req *gwapitypes.UserCreateRu func (c *Client) CreateUserLA(ctx context.Context, userRef string, req *gwapitypes.CreateUserLARequest) (*gwapitypes.CreateUserLAResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } la := new(gwapitypes.CreateUserLAResponse) resp, err := c.getParsedResponse(ctx, "POST", fmt.Sprintf("/users/%s/linkedaccounts", userRef), nil, jsonContent, bytes.NewReader(reqj), la) - return la, resp, err + return la, resp, errors.WithStack(err) } func (c *Client) DeleteUserLA(ctx context.Context, userRef, laID string) (*http.Response, error) { @@ -413,23 +416,23 @@ func (c *Client) DeleteUserLA(ctx context.Context, userRef, laID string) (*http. func (c *Client) RegisterUser(ctx context.Context, req *gwapitypes.RegisterUserRequest) (*gwapitypes.RegisterUserResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } res := new(gwapitypes.RegisterUserResponse) resp, err := c.getParsedResponse(ctx, "POST", "/auth/register", nil, jsonContent, bytes.NewReader(reqj), res) - return res, resp, err + return res, resp, errors.WithStack(err) } func (c *Client) CreateUserToken(ctx context.Context, userRef string, req *gwapitypes.CreateUserTokenRequest) (*gwapitypes.CreateUserTokenResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } tresp := new(gwapitypes.CreateUserTokenResponse) resp, err := c.getParsedResponse(ctx, "POST", fmt.Sprintf("/users/%s/tokens", userRef), nil, jsonContent, bytes.NewReader(reqj), tresp) - return tresp, resp, err + return tresp, resp, errors.WithStack(err) } func (c *Client) DeleteUserToken(ctx context.Context, userRef, tokenName string) (*http.Response, error) { @@ -439,13 +442,13 @@ func (c *Client) DeleteUserToken(ctx context.Context, userRef, tokenName string) func (c *Client) GetRun(ctx context.Context, runID string) (*gwapitypes.RunResponse, *http.Response, error) { run := new(gwapitypes.RunResponse) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/runs/%s", runID), nil, jsonContent, nil, run) - return run, resp, err + return run, resp, errors.WithStack(err) } func (c *Client) GetRunTask(ctx context.Context, runID, taskID string) (*gwapitypes.RunTaskResponse, *http.Response, error) { task := new(gwapitypes.RunTaskResponse) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/runs/%s/tasks/%s", runID, taskID), nil, jsonContent, nil, task) - return task, resp, err + return task, resp, errors.WithStack(err) } func (c *Client) GetRuns(ctx context.Context, phaseFilter, resultFilter, groups, runGroups []string, start string, limit int, asc bool) ([]*gwapitypes.RunsResponse, *http.Response, error) { @@ -474,7 +477,7 @@ func (c *Client) GetRuns(ctx context.Context, phaseFilter, resultFilter, groups, getRunsResponse := []*gwapitypes.RunsResponse{} resp, err := c.getParsedResponse(ctx, "GET", "/runs", q, jsonContent, nil, &getRunsResponse) - return getRunsResponse, resp, err + return getRunsResponse, resp, errors.WithStack(err) } func (c *Client) GetLogs(ctx context.Context, runID, taskID string, setup bool, step int, follow bool) (*http.Response, error) { @@ -508,7 +511,7 @@ func (c *Client) DeleteLogs(ctx context.Context, runID, taskID string, setup boo func (c *Client) GetRemoteSource(ctx context.Context, rsRef string) (*gwapitypes.RemoteSourceResponse, *http.Response, error) { rs := new(gwapitypes.RemoteSourceResponse) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/remotesources/%s", rsRef), nil, jsonContent, nil, rs) - return rs, resp, err + return rs, resp, errors.WithStack(err) } func (c *Client) GetRemoteSources(ctx context.Context, start string, limit int, asc bool) ([]*gwapitypes.RemoteSourceResponse, *http.Response, error) { @@ -525,29 +528,29 @@ func (c *Client) GetRemoteSources(ctx context.Context, start string, limit int, rss := []*gwapitypes.RemoteSourceResponse{} resp, err := c.getParsedResponse(ctx, "GET", "/remotesources", q, jsonContent, nil, &rss) - return rss, resp, err + return rss, resp, errors.WithStack(err) } func (c *Client) CreateRemoteSource(ctx context.Context, req *gwapitypes.CreateRemoteSourceRequest) (*gwapitypes.RemoteSourceResponse, *http.Response, error) { rsj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } rs := new(gwapitypes.RemoteSourceResponse) resp, err := c.getParsedResponse(ctx, "POST", "/remotesources", nil, jsonContent, bytes.NewReader(rsj), rs) - return rs, resp, err + return rs, resp, errors.WithStack(err) } func (c *Client) UpdateRemoteSource(ctx context.Context, rsRef string, req *gwapitypes.UpdateRemoteSourceRequest) (*gwapitypes.RemoteSourceResponse, *http.Response, error) { rsj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } rs := new(gwapitypes.RemoteSourceResponse) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/remotesources/%s", rsRef), nil, jsonContent, bytes.NewReader(rsj), rs) - return rs, resp, err + return rs, resp, errors.WithStack(err) } func (c *Client) DeleteRemoteSource(ctx context.Context, rsRef string) (*http.Response, error) { @@ -557,12 +560,12 @@ func (c *Client) DeleteRemoteSource(ctx context.Context, rsRef string) (*http.Re func (c *Client) CreateOrg(ctx context.Context, req *gwapitypes.CreateOrgRequest) (*gwapitypes.OrgResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } org := new(gwapitypes.OrgResponse) resp, err := c.getParsedResponse(ctx, "POST", "/orgs", nil, jsonContent, bytes.NewReader(reqj), org) - return org, resp, err + return org, resp, errors.WithStack(err) } func (c *Client) DeleteOrg(ctx context.Context, orgRef string) (*http.Response, error) { @@ -575,12 +578,12 @@ func (c *Client) AddOrgMember(ctx context.Context, orgRef, userRef string, role } omj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } res := new(gwapitypes.AddOrgMemberResponse) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/orgs/%s/members/%s", orgRef, userRef), nil, jsonContent, bytes.NewReader(omj), res) - return res, resp, err + return res, resp, errors.WithStack(err) } func (c *Client) RemoveOrgMember(ctx context.Context, orgRef, userRef string) (*http.Response, error) { @@ -590,17 +593,17 @@ func (c *Client) RemoveOrgMember(ctx context.Context, orgRef, userRef string) (* func (c *Client) GetOrgMembers(ctx context.Context, orgRef string) (*gwapitypes.OrgMembersResponse, *http.Response, error) { res := &gwapitypes.OrgMembersResponse{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/orgs/%s/members", orgRef), nil, jsonContent, nil, &res) - return res, resp, err + return res, resp, errors.WithStack(err) } func (c *Client) GetVersion(ctx context.Context) (*gwapitypes.VersionResponse, *http.Response, error) { res := &gwapitypes.VersionResponse{} resp, err := c.getParsedResponse(ctx, "GET", "/version", nil, jsonContent, nil, &res) - return res, resp, err + return res, resp, errors.WithStack(err) } func (c *Client) GetUserOrgs(ctx context.Context) ([]*gwapitypes.UserOrgsResponse, *http.Response, error) { userOrgs := []*gwapitypes.UserOrgsResponse{} resp, err := c.getParsedResponse(ctx, "GET", "/user/orgs", nil, jsonContent, nil, &userOrgs) - return userOrgs, resp, err + return userOrgs, resp, errors.WithStack(err) } diff --git a/services/runservice/client/client.go b/services/runservice/client/client.go index 8f093f9..8eac493 100644 --- a/services/runservice/client/client.go +++ b/services/runservice/client/client.go @@ -25,6 +25,7 @@ import ( "strconv" "strings" + "agola.io/agola/internal/errors" "agola.io/agola/internal/util" rsapitypes "agola.io/agola/services/runservice/api/types" rstypes "agola.io/agola/services/runservice/types" @@ -53,14 +54,14 @@ func (c *Client) SetHTTPClient(client *http.Client) { func (c *Client) doRequest(ctx context.Context, method, path string, query url.Values, contentLength int64, header http.Header, ibody io.Reader) (*http.Response, error) { u, err := url.Parse(c.url + "/api/v1alpha" + path) if err != nil { - return nil, err + return nil, errors.WithStack(err) } u.RawQuery = query.Encode() req, err := http.NewRequest(method, u.String(), ibody) req = req.WithContext(ctx) if err != nil { - return nil, err + return nil, errors.WithStack(err) } for k, v := range header { req.Header[k] = v @@ -70,17 +71,19 @@ func (c *Client) doRequest(ctx context.Context, method, path string, query url.V req.ContentLength = contentLength } - return c.client.Do(req) + res, err := c.client.Do(req) + + return res, errors.WithStack(err) } func (c *Client) getResponse(ctx context.Context, method, path string, query url.Values, contentLength int64, header http.Header, ibody io.Reader) (*http.Response, error) { resp, err := c.doRequest(ctx, method, path, query, contentLength, header, ibody) if err != nil { - return nil, err + return nil, errors.WithStack(err) } if err := util.ErrFromRemote(resp); err != nil { - return resp, err + return resp, errors.WithStack(err) } return resp, nil @@ -89,19 +92,19 @@ func (c *Client) getResponse(ctx context.Context, method, path string, query url func (c *Client) getParsedResponse(ctx context.Context, method, path string, query url.Values, header http.Header, ibody io.Reader, obj interface{}) (*http.Response, error) { resp, err := c.getResponse(ctx, method, path, query, -1, header, ibody) if err != nil { - return resp, err + return resp, errors.WithStack(err) } defer resp.Body.Close() d := json.NewDecoder(resp.Body) - return resp, d.Decode(obj) + return resp, errors.WithStack(d.Decode(obj)) } func (c *Client) SendExecutorStatus(ctx context.Context, executor *rstypes.Executor) (*http.Response, error) { executorj, err := json.Marshal(executor) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return c.getResponse(ctx, "POST", fmt.Sprintf("/executor/%s", executor.ID), nil, -1, jsonContent, bytes.NewReader(executorj)) } @@ -109,7 +112,7 @@ func (c *Client) SendExecutorStatus(ctx context.Context, executor *rstypes.Execu func (c *Client) SendExecutorTaskStatus(ctx context.Context, executorID string, et *rstypes.ExecutorTask) (*http.Response, error) { etj, err := json.Marshal(et) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return c.getResponse(ctx, "POST", fmt.Sprintf("/executor/%s/tasks/%s", executorID, et.ID), nil, -1, jsonContent, bytes.NewReader(etj)) } @@ -117,13 +120,13 @@ func (c *Client) SendExecutorTaskStatus(ctx context.Context, executorID string, func (c *Client) GetExecutorTask(ctx context.Context, executorID, etID string) (*rstypes.ExecutorTask, *http.Response, error) { et := new(rstypes.ExecutorTask) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/executor/%s/tasks/%s", executorID, etID), nil, jsonContent, nil, et) - return et, resp, err + return et, resp, errors.WithStack(err) } func (c *Client) GetExecutorTasks(ctx context.Context, executorID string) ([]*rstypes.ExecutorTask, *http.Response, error) { ets := []*rstypes.ExecutorTask{} resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/executor/%s/tasks", executorID), nil, jsonContent, nil, &ets) - return ets, resp, err + return ets, resp, errors.WithStack(err) } func (c *Client) GetArchive(ctx context.Context, taskID string, step int) (*http.Response, error) { @@ -183,7 +186,7 @@ func (c *Client) GetRuns(ctx context.Context, phaseFilter, resultFilter, groups getRunsResponse := new(rsapitypes.GetRunsResponse) resp, err := c.getParsedResponse(ctx, "GET", "/runs", q, jsonContent, nil, getRunsResponse) - return getRunsResponse, resp, err + return getRunsResponse, resp, errors.WithStack(err) } func (c *Client) GetQueuedRuns(ctx context.Context, start string, limit int, changeGroups []string) (*rsapitypes.GetRunsResponse, *http.Response, error) { @@ -213,18 +216,18 @@ func (c *Client) GetGroupLastRun(ctx context.Context, group string, changeGroups func (c *Client) CreateRun(ctx context.Context, req *rsapitypes.RunCreateRequest) (*rsapitypes.RunResponse, *http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, nil, err + return nil, nil, errors.WithStack(err) } res := new(rsapitypes.RunResponse) resp, err := c.getParsedResponse(ctx, "POST", "/runs", nil, jsonContent, bytes.NewReader(reqj), res) - return res, resp, err + return res, resp, errors.WithStack(err) } func (c *Client) RunActions(ctx context.Context, runID string, req *rsapitypes.RunActionsRequest) (*http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return c.getResponse(ctx, "PUT", fmt.Sprintf("/runs/%s/actions", runID), nil, -1, jsonContent, bytes.NewReader(reqj)) } @@ -242,7 +245,7 @@ func (c *Client) StartRun(ctx context.Context, runID string, changeGroupsUpdateT func (c *Client) RunTaskActions(ctx context.Context, runID, taskID string, req *rsapitypes.RunTaskActionsRequest) (*http.Response, error) { reqj, err := json.Marshal(req) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return c.getResponse(ctx, "PUT", fmt.Sprintf("/runs/%s/tasks/%s/actions", runID, taskID), nil, -1, jsonContent, bytes.NewReader(reqj)) } @@ -274,7 +277,7 @@ func (c *Client) GetRun(ctx context.Context, runID string, changeGroups []string runResponse := new(rsapitypes.RunResponse) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/runs/%s", runID), q, jsonContent, nil, runResponse) - return runResponse, resp, err + return runResponse, resp, errors.WithStack(err) } func (c *Client) GetLogs(ctx context.Context, runID, taskID string, setup bool, step int, follow bool) (*http.Response, error) { diff --git a/services/runservice/types/types.go b/services/runservice/types/types.go index 20f16d0..2b7ebd2 100644 --- a/services/runservice/types/types.go +++ b/services/runservice/types/types.go @@ -20,6 +20,7 @@ import ( "fmt" "time" + "agola.io/agola/internal/errors" "agola.io/agola/services/types" "agola.io/agola/util" @@ -568,20 +569,20 @@ func (et *Steps) UnmarshalJSON(b []byte) error { var rs rawSteps if err := json.Unmarshal(b, &rs); err != nil { - return err + return errors.WithStack(err) } steps := make(Steps, len(rs)) for i, step := range rs { var bs BaseStep if err := json.Unmarshal(step, &bs); err != nil { - return err + return errors.WithStack(err) } switch bs.Type { case "run": var s RunStep if err := json.Unmarshal(step, &s); err != nil { - return err + return errors.WithStack(err) } if s.Tty == nil { s.Tty = util.BoolP(true) @@ -590,25 +591,25 @@ func (et *Steps) UnmarshalJSON(b []byte) error { case "save_to_workspace": var s SaveToWorkspaceStep if err := json.Unmarshal(step, &s); err != nil { - return err + return errors.WithStack(err) } steps[i] = &s case "restore_workspace": var s RestoreWorkspaceStep if err := json.Unmarshal(step, &s); err != nil { - return err + return errors.WithStack(err) } steps[i] = &s case "save_cache": var s SaveCacheStep if err := json.Unmarshal(step, &s); err != nil { - return err + return errors.WithStack(err) } steps[i] = &s case "restore_cache": var s RestoreCacheStep if err := json.Unmarshal(step, &s); err != nil { - return err + return errors.WithStack(err) } steps[i] = &s } @@ -629,7 +630,7 @@ type ChangeGroupsRevisions map[string]int64 func MarshalChangeGroupsUpdateToken(t *ChangeGroupsUpdateToken) (string, error) { tj, err := json.Marshal(t) if err != nil { - return "", err + return "", errors.WithStack(err) } return base64.StdEncoding.EncodeToString(tj), nil } @@ -641,11 +642,11 @@ func UnmarshalChangeGroupsUpdateToken(s string) (*ChangeGroupsUpdateToken, error tj, err := base64.StdEncoding.DecodeString(s) if err != nil { - return nil, err + return nil, errors.WithStack(err) } var t *ChangeGroupsUpdateToken if err := json.Unmarshal(tj, &t); err != nil { - return nil, err + return nil, errors.WithStack(err) } return t, nil } diff --git a/tests/setup_test.go b/tests/setup_test.go index ebf6ff9..b92eaa2 100644 --- a/tests/setup_test.go +++ b/tests/setup_test.go @@ -27,6 +27,7 @@ import ( "testing" "time" + "agola.io/agola/internal/errors" "agola.io/agola/internal/services/config" "agola.io/agola/internal/services/configstore" "agola.io/agola/internal/services/executor" @@ -44,7 +45,6 @@ import ( "code.gitea.io/sdk/gitea" "github.com/google/go-cmp/cmp" "github.com/rs/zerolog" - errors "golang.org/x/xerrors" "gopkg.in/src-d/go-billy.v4/memfs" "gopkg.in/src-d/go-billy.v4/osfs" "gopkg.in/src-d/go-git.v4" @@ -140,37 +140,37 @@ func shutdownGitea(tgitea *testutil.TestGitea) { func startAgola(ctx context.Context, t *testing.T, log zerolog.Logger, dir string, c *config.Config) (<-chan error, error) { rs, err := rsscheduler.NewRunservice(ctx, log, &c.Runservice) if err != nil { - return nil, errors.Errorf("failed to start run service scheduler: %w", err) + return nil, errors.Wrapf(err, "failed to start run service scheduler") } ex, err := executor.NewExecutor(ctx, log, &c.Executor) if err != nil { - return nil, errors.Errorf("failed to start run service executor: %w", err) + return nil, errors.Wrapf(err, "failed to start run service executor") } cs, err := configstore.NewConfigstore(ctx, log, &c.Configstore) if err != nil { - return nil, errors.Errorf("failed to start config store: %w", err) + return nil, errors.Wrapf(err, "failed to start config store") } sched, err := scheduler.NewScheduler(ctx, log, &c.Scheduler) if err != nil { - return nil, errors.Errorf("failed to start scheduler: %w", err) + return nil, errors.Wrapf(err, "failed to start scheduler") } ns, err := notification.NewNotificationService(ctx, log, c) if err != nil { - return nil, errors.Errorf("failed to start notification service: %w", err) + return nil, errors.Wrapf(err, "failed to start notification service") } gw, err := gateway.NewGateway(ctx, log, c) if err != nil { - return nil, errors.Errorf("failed to start gateway: %w", err) + return nil, errors.Wrapf(err, "failed to start gateway") } gs, err := gitserver.NewGitserver(ctx, log, &c.Gitserver) if err != nil { - return nil, errors.Errorf("failed to start git server: %w", err) + return nil, errors.Wrapf(err, "failed to start git server") } errCh := make(chan error) @@ -358,7 +358,7 @@ func setup(ctx context.Context, t *testing.T, dir string) (*testutil.TestEmbedde go func() { err := <-errCh if err != nil { - panic(fmt.Errorf("agola component returned error: %w", err)) + panic(errors.Wrap(err, "agola component returned error: %w")) } }()