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