*: use new errors handling library

Implement a new error handling library based on pkg/errors. It provides
stack saving on wrapping and exports some function to add stack saving
also to external errors.
It also implements custom zerolog error formatting without adding too
much verbosity by just printing the chain error file:line without a full
stack trace of every error.

* Add a --detailed-errors options to print error with they full chain
* Wrap all error returns. Use errors.WithStack to wrap without adding a
  new messsage and error.Wrap[f] to add a message.
* Add golangci-lint wrapcheck to check that external packages errors are
  wrapped. This won't check that internal packages error are wrapped.
  But we want also to ensure this case so we'll have to find something
  else to check also these.
This commit is contained in:
Simone Gotti 2022-02-22 15:01:29 +01:00
parent 5df9ee19c4
commit d2b09d854f
183 changed files with 2912 additions and 2348 deletions

View File

@ -1,2 +1,25 @@
linters: 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/*

View File

@ -20,19 +20,20 @@ import (
"time" "time"
"agola.io/agola/cmd" "agola.io/agola/cmd"
"agola.io/agola/internal/errors"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var token string var token string
func init() { func init() {
cw := zerolog.ConsoleWriter{ cw := zerolog.ConsoleWriter{
Out: os.Stderr, Out: os.Stderr,
TimeFormat: time.RFC3339Nano, TimeFormat: time.RFC3339Nano,
FormatErrFieldValue: errors.FormatErrFieldValue,
} }
zerolog.TimeFieldFormat = time.RFC3339Nano zerolog.TimeFieldFormat = time.RFC3339Nano
@ -53,6 +54,9 @@ var cmdAgola = &cobra.Command{
if agolaOpts.debug { if agolaOpts.debug {
log.Logger = log.Level(zerolog.DebugLevel) log.Logger = log.Level(zerolog.DebugLevel)
} }
if agolaOpts.detailedErrors {
zerolog.ErrorMarshalFunc = errors.ErrorMarshalFunc
}
}, },
Run: func(c *cobra.Command, args []string) { Run: func(c *cobra.Command, args []string) {
if err := c.Help(); err != nil { if err := c.Help(); err != nil {
@ -62,8 +66,9 @@ var cmdAgola = &cobra.Command{
} }
type agolaOptions struct { type agolaOptions struct {
gatewayURL string gatewayURL string
debug bool debug bool
detailedErrors bool
} }
var agolaOpts agolaOptions var agolaOpts agolaOptions
@ -84,6 +89,7 @@ func init() {
flags.StringVarP(&agolaOpts.gatewayURL, "gateway-url", "u", gatewayURL, "agola gateway exposed url") flags.StringVarP(&agolaOpts.gatewayURL, "gateway-url", "u", gatewayURL, "agola gateway exposed url")
flags.StringVar(&token, "token", token, "api token") flags.StringVar(&token, "token", token, "api token")
flags.BoolVarP(&agolaOpts.debug, "debug", "d", false, "debug") flags.BoolVarP(&agolaOpts.debug, "debug", "d", false, "debug")
flags.BoolVar(&agolaOpts.detailedErrors, "detailed-errors", false, "enabled detailed errors logging")
} }
func Execute() { func Execute() {

View File

@ -17,6 +17,7 @@ package cmd
import ( import (
"os" "os"
"agola.io/agola/internal/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -33,11 +34,11 @@ func completionShell(cmd *cobra.Command, args []string, shell string) error {
switch shell { switch shell {
case "bash": case "bash":
if err := cmdAgola.GenBashCompletion(os.Stdout); err != nil { if err := cmdAgola.GenBashCompletion(os.Stdout); err != nil {
return err return errors.WithStack(err)
} }
case "zsh": case "zsh":
if err := cmdAgola.GenZshCompletion(os.Stdout); err != nil { if err := cmdAgola.GenZshCompletion(os.Stdout); err != nil {
return err return errors.WithStack(err)
} }
} }
return nil return nil

View File

@ -23,6 +23,7 @@ import (
"strings" "strings"
"unicode" "unicode"
"agola.io/agola/internal/errors"
gitsave "agola.io/agola/internal/git-save" gitsave "agola.io/agola/internal/git-save"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
@ -32,7 +33,6 @@ import (
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdDirectRunStart = &cobra.Command{ var cmdDirectRunStart = &cobra.Command{
@ -80,15 +80,15 @@ func parseVariable(variable string) (string, string, error) {
variable = strings.TrimLeftFunc(variable, unicode.IsSpace) variable = strings.TrimLeftFunc(variable, unicode.IsSpace)
arr := strings.SplitN(variable, "=", 2) arr := strings.SplitN(variable, "=", 2)
if len(arr) != 2 { if len(arr) != 2 {
return "", "", fmt.Errorf("invalid variable definition: %s", variable) return "", "", errors.Errorf("invalid variable definition: %s", variable)
} }
varname := arr[0] varname := arr[0]
varvalue := arr[1] varvalue := arr[1]
if varname == "" { if varname == "" {
return "", "", fmt.Errorf("invalid variable definition: %s", variable) return "", "", errors.Errorf("invalid variable definition: %s", variable)
} }
if varvalue == "" { if varvalue == "" {
return "", "", fmt.Errorf("invalid variable definition: %s", variable) return "", "", errors.Errorf("invalid variable definition: %s", variable)
} }
return varname, varvalue, nil return varname, varvalue, nil
} }
@ -98,7 +98,7 @@ func directRunStart(cmd *cobra.Command, args []string) error {
for _, res := range directRunStartOpts.prRefRegexes { for _, res := range directRunStartOpts.prRefRegexes {
if _, err := regexp.Compile(res); err != nil { 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 = "" branch = ""
} }
if set > 1 { 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()) user, _, err := gwclient.GetCurrentUser(context.TODO())
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
variables := map[string]string{} variables := map[string]string{}
@ -142,11 +142,11 @@ func directRunStart(cmd *cobra.Command, args []string) error {
var err error var err error
data, err = ioutil.ReadFile(varFile) data, err = ioutil.ReadFile(varFile)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if err := yaml.Unmarshal(data, &variables); err != nil { 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 // TODO(sgotti) validate variable name
@ -155,7 +155,7 @@ func directRunStart(cmd *cobra.Command, args []string) error {
for _, variable := range directRunStartOpts.vars { for _, variable := range directRunStartOpts.vars {
varname, varvalue, err := parseVariable(variable) varname, varvalue, err := parseVariable(variable)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
variables[varname] = varvalue variables[varname] = varvalue
} }
@ -166,7 +166,7 @@ func directRunStart(cmd *cobra.Command, args []string) error {
if repoUUID == "" { if repoUUID == "" {
repoUUID = uuid.Must(uuid.NewV4()).String() repoUUID = uuid.Must(uuid.NewV4()).String()
if _, err := git.ConfigSet(context.Background(), "agola.repouuid", repoUUID); err != nil { 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) commitSHA, err := gs.Save(message, localBranch)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
log.Info().Msgf("pushing branch") 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" // push to a branch with default branch refs "refs/heads/branch"
if branch != "" { if branch != "" {
if err := gitsave.GitPush("", repoURL, fmt.Sprintf("%s:refs/heads/%s", path.Join(gs.RefsPrefix(), localBranch), branch)); err != nil { 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 != "" { } else if tag != "" {
if err := gitsave.GitPush("", repoURL, fmt.Sprintf("%s:refs/tags/%s", path.Join(gs.RefsPrefix(), localBranch), tag)); err != nil { 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 != "" { } else if ref != "" {
if err := gitsave.GitPush("", repoURL, fmt.Sprintf("%s:%s", path.Join(gs.RefsPrefix(), localBranch), ref)); err != nil { 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, Variables: variables,
} }
if _, err := gwclient.UserCreateRun(context.TODO(), req); err != nil { if _, err := gwclient.UserCreateRun(context.TODO(), req); err != nil {
return err return errors.WithStack(err)
} }
return nil return nil

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdLogDelete = &cobra.Command{ var cmdLogDelete = &cobra.Command{
@ -93,7 +93,7 @@ func logDelete(cmd *cobra.Command, args []string) error {
run, _, err := gwclient.GetRun(context.TODO(), logDeleteOpts.runid) run, _, err := gwclient.GetRun(context.TODO(), logDeleteOpts.runid)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
for _, t := range run.Tasks { for _, t := range run.Tasks {
if t.Name == logDeleteOpts.taskname { if t.Name == logDeleteOpts.taskname {

View File

@ -19,12 +19,12 @@ import (
"io" "io"
"os" "os"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdLogGet = &cobra.Command{ var cmdLogGet = &cobra.Command{
@ -102,7 +102,7 @@ func logGet(cmd *cobra.Command, args []string) error {
run, _, err := gwclient.GetRun(context.TODO(), logGetOpts.runid) run, _, err := gwclient.GetRun(context.TODO(), logGetOpts.runid)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
for _, t := range run.Tasks { for _, t := range run.Tasks {
if t.Name == logGetOpts.taskname { if t.Name == logGetOpts.taskname {
@ -127,7 +127,7 @@ func logGet(cmd *cobra.Command, args []string) error {
if flags.Changed("output") { if flags.Changed("output") {
f, err := os.Create(logGetOpts.output) f, err := os.Create(logGetOpts.output)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer f.Close() defer f.Close()
if _, err := io.Copy(f, resp.Body); err != nil { if _, err := io.Copy(f, resp.Body); err != nil {

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdOrgCreate = &cobra.Command{ var cmdOrgCreate = &cobra.Command{
@ -71,7 +71,7 @@ func orgCreate(cmd *cobra.Command, args []string) error {
log.Info().Msgf("creating org") log.Info().Msgf("creating org")
org, _, err := gwclient.CreateOrg(context.TODO(), req) org, _, err := gwclient.CreateOrg(context.TODO(), req)
if err != nil { 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) log.Info().Msgf("org %q created, ID: %q", org.Name, org.ID)

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdOrgDelete = &cobra.Command{ var cmdOrgDelete = &cobra.Command{
@ -57,7 +57,7 @@ func orgDelete(cmd *cobra.Command, args []string) error {
log.Info().Msgf("deleting organization %q", orgDeleteOpts.name) log.Info().Msgf("deleting organization %q", orgDeleteOpts.name)
if _, err := gwclient.DeleteOrg(context.TODO(), orgDeleteOpts.name); err != nil { 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 return nil

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdOrgMemberAdd = &cobra.Command{ 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) 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)) _, _, err := gwclient.AddOrgMember(context.TODO(), orgMemberAddOpts.orgname, orgMemberAddOpts.username, gwapitypes.MemberRole(orgMemberAddOpts.role))
if err != nil { 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 return nil

View File

@ -19,11 +19,11 @@ import (
"encoding/json" "encoding/json"
"os" "os"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdOrgMemberList = &cobra.Command{ var cmdOrgMemberList = &cobra.Command{
@ -59,12 +59,12 @@ func orgMemberList(cmd *cobra.Command, args []string) error {
orgMembers, _, err := gwclient.GetOrgMembers(context.TODO(), orgMemberListOpts.orgname) orgMembers, _, err := gwclient.GetOrgMembers(context.TODO(), orgMemberListOpts.orgname)
if err != nil { 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") out, err := json.MarshalIndent(orgMembers, "", "\t")
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
os.Stdout.Write(out) os.Stdout.Write(out)

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdOrgMemberRemove = &cobra.Command{ 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) log.Info().Msgf("removing member %q from organization %q", orgMemberRemoveOpts.username, orgMemberRemoveOpts.orgname)
_, err := gwclient.RemoveOrgMember(context.TODO(), orgMemberRemoveOpts.orgname, orgMemberRemoveOpts.username) _, err := gwclient.RemoveOrgMember(context.TODO(), orgMemberRemoveOpts.orgname, orgMemberRemoveOpts.username)
if err != nil { if err != nil {
return errors.Errorf("failed to remove organization member: %w", err) return errors.Wrapf(err, "failed to remove organization member")
} }
return nil return nil

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectCreate = &cobra.Command{ var cmdProjectCreate = &cobra.Command{
@ -106,7 +106,7 @@ func projectCreate(cmd *cobra.Command, args []string) error {
project, _, err := gwclient.CreateProject(context.TODO(), req) project, _, err := gwclient.CreateProject(context.TODO(), req)
if err != nil { 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) log.Info().Msgf("project %s created, ID: %s", project.Name, project.ID)

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectDelete = &cobra.Command{ var cmdProjectDelete = &cobra.Command{
@ -58,7 +58,7 @@ func projectDelete(cmd *cobra.Command, args []string) error {
log.Info().Msgf("deleting project") log.Info().Msgf("deleting project")
if _, err := gwclient.DeleteProject(context.TODO(), projectDeleteOpts.ref); err != nil { 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 return nil

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectGroupCreate = &cobra.Command{ var cmdProjectGroupCreate = &cobra.Command{
@ -78,7 +78,7 @@ func projectGroupCreate(cmd *cobra.Command, args []string) error {
projectGroup, _, err := gwclient.CreateProjectGroup(context.TODO(), req) projectGroup, _, err := gwclient.CreateProjectGroup(context.TODO(), req)
if err != nil { 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) log.Info().Msgf("project group %s created, ID: %s", projectGroup.Name, projectGroup.ID)

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectGroupDelete = &cobra.Command{ var cmdProjectGroupDelete = &cobra.Command{
@ -58,7 +58,7 @@ func projectGroupDelete(cmd *cobra.Command, args []string) error {
log.Info().Msgf("deleting project group") log.Info().Msgf("deleting project group")
if _, err := gwclient.DeleteProjectGroup(context.TODO(), projectGroupDeleteOpts.ref); err != nil { 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 return nil

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectGroupUpdate = &cobra.Command{ var cmdProjectGroupUpdate = &cobra.Command{
@ -82,7 +82,7 @@ func projectGroupUpdate(cmd *cobra.Command, args []string) error {
log.Info().Msgf("updating project group") log.Info().Msgf("updating project group")
projectGroup, _, err := gwclient.UpdateProjectGroup(context.TODO(), projectGroupUpdateOpts.ref, req) projectGroup, _, err := gwclient.UpdateProjectGroup(context.TODO(), projectGroupUpdateOpts.ref, req)
if err != nil { 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) log.Info().Msgf("project group %s update, ID: %s", projectGroup.Name, projectGroup.ID)

View File

@ -18,6 +18,7 @@ import (
"context" "context"
"fmt" "fmt"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" 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) projects, _, err := gwclient.GetProjectGroupProjects(context.TODO(), projectListOpts.parentPath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
printProjects(projects) printProjects(projects)

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectReconfig = &cobra.Command{ var cmdProjectReconfig = &cobra.Command{
@ -57,7 +57,7 @@ func projectReconfig(cmd *cobra.Command, args []string) error {
log.Info().Msgf("reconfiguring remote project") log.Info().Msgf("reconfiguring remote project")
if _, err := gwclient.ReconfigProject(context.TODO(), projectReconfigOpts.name); err != nil { 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") log.Info().Msgf("project reconfigured")

View File

@ -19,13 +19,13 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectSecretCreate = &cobra.Command{ var cmdProjectSecretCreate = &cobra.Command{
@ -82,12 +82,12 @@ func secretCreate(cmd *cobra.Command, ownertype string, args []string) error {
if secretCreateOpts.file == "-" { if secretCreateOpts.file == "-" {
data, err = ioutil.ReadAll(os.Stdin) data, err = ioutil.ReadAll(os.Stdin)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
} else { } else {
data, err = ioutil.ReadFile(secretCreateOpts.file) data, err = ioutil.ReadFile(secretCreateOpts.file)
if err != nil { 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") log.Info().Msgf("creating project secret")
secret, _, err := gwclient.CreateProjectSecret(context.TODO(), secretCreateOpts.parentRef, req) secret, _, err := gwclient.CreateProjectSecret(context.TODO(), secretCreateOpts.parentRef, req)
if err != nil { 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) log.Info().Msgf("project secret %q created, ID: %q", secret.Name, secret.ID)
case "projectgroup": case "projectgroup":
log.Info().Msgf("creating project group secret") log.Info().Msgf("creating project group secret")
secret, _, err := gwclient.CreateProjectGroupSecret(context.TODO(), secretCreateOpts.parentRef, req) secret, _, err := gwclient.CreateProjectGroupSecret(context.TODO(), secretCreateOpts.parentRef, req)
if err != nil { 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) log.Info().Msgf("project group secret %q created, ID: %q", secret.Name, secret.ID)
} }

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectSecretDelete = &cobra.Command{ var cmdProjectSecretDelete = &cobra.Command{
@ -65,14 +65,14 @@ func secretDelete(cmd *cobra.Command, ownertype string, args []string) error {
log.Info().Msgf("deleting project secret") log.Info().Msgf("deleting project secret")
_, err := gwclient.DeleteProjectSecret(context.TODO(), secretDeleteOpts.parentRef, secretDeleteOpts.name) _, err := gwclient.DeleteProjectSecret(context.TODO(), secretDeleteOpts.parentRef, secretDeleteOpts.name)
if err != nil { 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") log.Info().Msgf("project secret deleted")
case "projectgroup": case "projectgroup":
log.Info().Msgf("deleting project group secret") log.Info().Msgf("deleting project group secret")
_, err := gwclient.DeleteProjectGroupSecret(context.TODO(), secretDeleteOpts.parentRef, secretDeleteOpts.name) _, err := gwclient.DeleteProjectGroupSecret(context.TODO(), secretDeleteOpts.parentRef, secretDeleteOpts.name)
if err != nil { 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") log.Info().Msgf("project group secret deleted")
} }

View File

@ -19,12 +19,12 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectSecretList = &cobra.Command{ var cmdProjectSecretList = &cobra.Command{
@ -57,10 +57,10 @@ func init() {
func secretList(cmd *cobra.Command, ownertype string, args []string) error { func secretList(cmd *cobra.Command, ownertype string, args []string) error {
if err := printSecrets(ownertype, fmt.Sprintf("%s secrets", ownertype), false, false); err != nil { 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 { if err := printSecrets(ownertype, "All secrets (local and inherited)", true, true); err != nil {
return err return errors.WithStack(err)
} }
return nil 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) secrets, _, err = gwclient.GetProjectGroupSecrets(context.TODO(), secretListOpts.parentRef, tree, removeoverridden)
} }
if err != nil { 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") prettyJSON, err := json.MarshalIndent(secrets, "", "\t")
if err != nil { 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)) fmt.Printf("%s:\n%s\n", description, string(prettyJSON))
return nil return nil

View File

@ -19,13 +19,13 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectSecretUpdate = &cobra.Command{ var cmdProjectSecretUpdate = &cobra.Command{
@ -84,12 +84,12 @@ func secretUpdate(cmd *cobra.Command, ownertype string, args []string) error {
if secretUpdateOpts.file == "-" { if secretUpdateOpts.file == "-" {
data, err = ioutil.ReadAll(os.Stdin) data, err = ioutil.ReadAll(os.Stdin)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
} else { } else {
data, err = ioutil.ReadFile(secretUpdateOpts.file) data, err = ioutil.ReadFile(secretUpdateOpts.file)
if err != nil { 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") log.Info().Msgf("creating project secret")
secret, _, err := gwclient.UpdateProjectSecret(context.TODO(), secretUpdateOpts.parentRef, secretUpdateOpts.name, req) secret, _, err := gwclient.UpdateProjectSecret(context.TODO(), secretUpdateOpts.parentRef, secretUpdateOpts.name, req)
if err != nil { 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) log.Info().Msgf("project secret %q updated, ID: %q", secret.Name, secret.ID)
case "projectgroup": case "projectgroup":
log.Info().Msgf("creating project group secret") log.Info().Msgf("creating project group secret")
secret, _, err := gwclient.UpdateProjectGroupSecret(context.TODO(), secretUpdateOpts.parentRef, secretUpdateOpts.name, req) secret, _, err := gwclient.UpdateProjectGroupSecret(context.TODO(), secretUpdateOpts.parentRef, secretUpdateOpts.name, req)
if err != nil { 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) log.Info().Msgf("project group secret %q updated, ID: %q", secret.Name, secret.ID)
} }

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectUpdate = &cobra.Command{ var cmdProjectUpdate = &cobra.Command{
@ -88,7 +88,7 @@ func projectUpdate(cmd *cobra.Command, args []string) error {
log.Info().Msgf("updating project") log.Info().Msgf("updating project")
project, _, err := gwclient.UpdateProject(context.TODO(), projectUpdateOpts.ref, req) project, _, err := gwclient.UpdateProject(context.TODO(), projectUpdateOpts.ref, req)
if err != nil { 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) log.Info().Msgf("project %s update, ID: %s", project.Name, project.ID)

View File

@ -20,13 +20,13 @@ import (
"os" "os"
config "agola.io/agola/internal/config" config "agola.io/agola/internal/config"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectVariableCreate = &cobra.Command{ var cmdProjectVariableCreate = &cobra.Command{
@ -105,12 +105,12 @@ func variableCreate(cmd *cobra.Command, ownertype string, args []string) error {
if variableCreateOpts.file == "-" { if variableCreateOpts.file == "-" {
data, err = ioutil.ReadAll(os.Stdin) data, err = ioutil.ReadAll(os.Stdin)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
} else { } else {
data, err = ioutil.ReadFile(variableCreateOpts.file) data, err = ioutil.ReadFile(variableCreateOpts.file)
if err != nil { 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") log.Info().Msgf("creating project variable")
variable, _, err := gwclient.CreateProjectVariable(context.TODO(), variableCreateOpts.parentRef, req) variable, _, err := gwclient.CreateProjectVariable(context.TODO(), variableCreateOpts.parentRef, req)
if err != nil { 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) log.Info().Msgf("project variable %q created, ID: %q", variable.Name, variable.ID)
case "projectgroup": case "projectgroup":
log.Info().Msgf("creating project group variable") log.Info().Msgf("creating project group variable")
variable, _, err := gwclient.CreateProjectGroupVariable(context.TODO(), variableCreateOpts.parentRef, req) variable, _, err := gwclient.CreateProjectGroupVariable(context.TODO(), variableCreateOpts.parentRef, req)
if err != nil { 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) log.Info().Msgf("project group variable %q created, ID: %q", variable.Name, variable.ID)
} }

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectVariableDelete = &cobra.Command{ var cmdProjectVariableDelete = &cobra.Command{
@ -65,14 +65,14 @@ func variableDelete(cmd *cobra.Command, ownertype string, args []string) error {
log.Info().Msgf("deleting project variable") log.Info().Msgf("deleting project variable")
_, err := gwclient.DeleteProjectVariable(context.TODO(), variableDeleteOpts.parentRef, variableDeleteOpts.name) _, err := gwclient.DeleteProjectVariable(context.TODO(), variableDeleteOpts.parentRef, variableDeleteOpts.name)
if err != nil { 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") log.Info().Msgf("project variable deleted")
case "projectgroup": case "projectgroup":
log.Info().Msgf("deleting project group variable") log.Info().Msgf("deleting project group variable")
_, err := gwclient.DeleteProjectGroupVariable(context.TODO(), variableDeleteOpts.parentRef, variableDeleteOpts.name) _, err := gwclient.DeleteProjectGroupVariable(context.TODO(), variableDeleteOpts.parentRef, variableDeleteOpts.name)
if err != nil { 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") log.Info().Msgf("project group variable deleted")
} }

View File

@ -19,12 +19,12 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectVariableList = &cobra.Command{ var cmdProjectVariableList = &cobra.Command{
@ -57,10 +57,10 @@ func init() {
func variableList(cmd *cobra.Command, ownertype string, args []string) error { func variableList(cmd *cobra.Command, ownertype string, args []string) error {
if err := printVariables(ownertype, fmt.Sprintf("%s variables", ownertype), false, false); err != nil { 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 { if err := printVariables(ownertype, "All variables (local and inherited)", true, true); err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
} }
@ -79,11 +79,11 @@ func printVariables(ownertype, description string, tree, removeoverridden bool)
variables, _, err = gwclient.GetProjectGroupVariables(context.TODO(), variableListOpts.parentRef, tree, removeoverridden) variables, _, err = gwclient.GetProjectGroupVariables(context.TODO(), variableListOpts.parentRef, tree, removeoverridden)
} }
if err != nil { 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") prettyJSON, err := json.MarshalIndent(variables, "", "\t")
if err != nil { 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)) fmt.Printf("%s:\n%s\n", description, string(prettyJSON))
return nil return nil

View File

@ -19,13 +19,13 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdProjectVariableUpdate = &cobra.Command{ var cmdProjectVariableUpdate = &cobra.Command{
@ -77,12 +77,12 @@ func variableUpdate(cmd *cobra.Command, ownertype string, args []string) error {
if variableUpdateOpts.file == "-" { if variableUpdateOpts.file == "-" {
data, err = ioutil.ReadAll(os.Stdin) data, err = ioutil.ReadAll(os.Stdin)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
} else { } else {
data, err = ioutil.ReadFile(variableUpdateOpts.file) data, err = ioutil.ReadFile(variableUpdateOpts.file)
if err != nil { 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") log.Info().Msgf("updating project variable")
variable, _, err := gwclient.UpdateProjectVariable(context.TODO(), variableUpdateOpts.parentRef, variableUpdateOpts.name, req) variable, _, err := gwclient.UpdateProjectVariable(context.TODO(), variableUpdateOpts.parentRef, variableUpdateOpts.name, req)
if err != nil { 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) log.Info().Msgf("project variable %q updated, ID: %q", variable.Name, variable.ID)
case "projectgroup": case "projectgroup":
log.Info().Msgf("updating project group variable") log.Info().Msgf("updating project group variable")
variable, _, err := gwclient.UpdateProjectGroupVariable(context.TODO(), variableUpdateOpts.parentRef, variableUpdateOpts.name, req) variable, _, err := gwclient.UpdateProjectGroupVariable(context.TODO(), variableUpdateOpts.parentRef, variableUpdateOpts.name, req)
if err != nil { 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) log.Info().Msgf("project group variable %q updated, ID: %q", variable.Name, variable.ID)
} }

View File

@ -17,6 +17,7 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/gitsources/github" "agola.io/agola/internal/gitsources/github"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
@ -24,7 +25,6 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdRemoteSourceCreate = &cobra.Command{ var cmdRemoteSourceCreate = &cobra.Command{
@ -117,7 +117,7 @@ func remoteSourceCreate(cmd *cobra.Command, args []string) error {
log.Info().Msgf("creating remotesource") log.Info().Msgf("creating remotesource")
remoteSource, _, err := gwclient.CreateRemoteSource(context.TODO(), req) remoteSource, _, err := gwclient.CreateRemoteSource(context.TODO(), req)
if err != nil { 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) log.Info().Msgf("remotesource %s created, ID: %s", remoteSource.Name, remoteSource.ID)

View File

@ -18,6 +18,7 @@ import (
"context" "context"
"fmt" "fmt"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" 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) remouteSources, _, err := gwclient.GetRemoteSources(context.TODO(), remoteSourceListOpts.start, remoteSourceListOpts.limit, false)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
printRemoteSources(remouteSources) printRemoteSources(remouteSources)

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdRemoteSourceUpdate = &cobra.Command{ var cmdRemoteSourceUpdate = &cobra.Command{
@ -109,7 +109,7 @@ func remoteSourceUpdate(cmd *cobra.Command, args []string) error {
log.Info().Msgf("updating remotesource") log.Info().Msgf("updating remotesource")
remoteSource, _, err := gwclient.UpdateRemoteSource(context.TODO(), remoteSourceUpdateOpts.ref, req) remoteSource, _, err := gwclient.UpdateRemoteSource(context.TODO(), remoteSourceUpdateOpts.ref, req)
if err != nil { 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) log.Info().Msgf("remotesource %s updated, ID: %s", remoteSource.Name, remoteSource.ID)

View File

@ -16,8 +16,8 @@ package cmd
import ( import (
"context" "context"
"fmt"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
@ -76,7 +76,7 @@ func runCreate(cmd *cobra.Command, args []string) error {
set++ set++
} }
if set != 1 { 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{ req := &gwapitypes.ProjectCreateRunRequest{
@ -88,5 +88,5 @@ func runCreate(cmd *cobra.Command, args []string) error {
_, err := gwclient.ProjectCreateRun(context.TODO(), runCreateOpts.projectRef, req) _, err := gwclient.ProjectCreateRun(context.TODO(), runCreateOpts.projectRef, req)
return err return errors.WithStack(err)
} }

View File

@ -20,9 +20,9 @@ import (
"path" "path"
"sort" "sort"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
errors "golang.org/x/xerrors"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -104,14 +104,14 @@ func runList(cmd *cobra.Command, args []string) error {
groups := []string{path.Join("/project", project.ID)} groups := []string{path.Join("/project", project.ID)}
runsResp, _, err := gwclient.GetRuns(context.TODO(), runListOpts.phaseFilter, nil, groups, nil, runListOpts.start, runListOpts.limit, false) runsResp, _, err := gwclient.GetRuns(context.TODO(), runListOpts.phaseFilter, nil, groups, nil, runListOpts.start, runListOpts.limit, false)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
runs := make([]*runDetails, len(runsResp)) runs := make([]*runDetails, len(runsResp))
for i, runResponse := range runsResp { for i, runResponse := range runsResp {
run, _, err := gwclient.GetRun(context.TODO(), runResponse.ID) run, _, err := gwclient.GetRun(context.TODO(), runResponse.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
tasks := []*taskDetails{} tasks := []*taskDetails{}

View File

@ -19,6 +19,7 @@ import (
"fmt" "fmt"
"agola.io/agola/cmd" "agola.io/agola/cmd"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/services/config" "agola.io/agola/internal/services/config"
"agola.io/agola/internal/services/configstore" "agola.io/agola/internal/services/configstore"
"agola.io/agola/internal/services/executor" "agola.io/agola/internal/services/executor"
@ -33,7 +34,6 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"go.etcd.io/etcd/embed" "go.etcd.io/etcd/embed"
errors "golang.org/x/xerrors"
) )
var ( var (
@ -96,7 +96,7 @@ func embeddedEtcd(ctx context.Context) error {
log.Info().Msgf("starting embedded etcd server") log.Info().Msgf("starting embedded etcd server")
e, err := embed.StartEtcd(cfg) e, err := embed.StartEtcd(cfg)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
go func() { go func() {
@ -132,12 +132,12 @@ func serve(cmd *cobra.Command, args []string) error {
c, err := config.Parse(serveOpts.config, serveOpts.components) c, err := config.Parse(serveOpts.config, serveOpts.components)
if err != nil { if err != nil {
return errors.Errorf("config error: %w", err) return errors.Wrapf(err, "config error")
} }
if serveOpts.embeddedEtcd { if serveOpts.embeddedEtcd {
if err := embeddedEtcd(ctx); err != nil { 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") { if isComponentEnabled("runservice") {
rs, err = rsscheduler.NewRunservice(ctx, log.Logger, &c.Runservice) rs, err = rsscheduler.NewRunservice(ctx, log.Logger, &c.Runservice)
if err != nil { 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") { if isComponentEnabled("executor") {
ex, err = executor.NewExecutor(ctx, log.Logger, &c.Executor) ex, err = executor.NewExecutor(ctx, log.Logger, &c.Executor)
if err != nil { 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") { if isComponentEnabled("configstore") {
cs, err = configstore.NewConfigstore(ctx, log.Logger, &c.Configstore) cs, err = configstore.NewConfigstore(ctx, log.Logger, &c.Configstore)
if err != nil { 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") { if isComponentEnabled("scheduler") {
sched, err = scheduler.NewScheduler(ctx, log.Logger, &c.Scheduler) sched, err = scheduler.NewScheduler(ctx, log.Logger, &c.Scheduler)
if err != nil { 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") { if isComponentEnabled("notification") {
ns, err = notification.NewNotificationService(ctx, log.Logger, c) ns, err = notification.NewNotificationService(ctx, log.Logger, c)
if err != nil { 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") { if isComponentEnabled("gateway") {
gw, err = gateway.NewGateway(ctx, log.Logger, c) gw, err = gateway.NewGateway(ctx, log.Logger, c)
if err != nil { 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") { if isComponentEnabled("gitserver") {
gs, err = gitserver.NewGitserver(ctx, log.Logger, &c.Gitserver) gs, err = gitserver.NewGitserver(ctx, log.Logger, &c.Gitserver)
if err != nil { if err != nil {
return errors.Errorf("failed to start git server: %w", err) return errors.Wrapf(err, "failed to start git server")
} }
} }

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdUserCreate = &cobra.Command{ var cmdUserCreate = &cobra.Command{
@ -63,7 +63,7 @@ func userCreate(cmd *cobra.Command, args []string) error {
log.Info().Msgf("creating user") log.Info().Msgf("creating user")
user, _, err := gwclient.CreateUser(context.TODO(), req) user, _, err := gwclient.CreateUser(context.TODO(), req)
if err != nil { 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) log.Info().Msgf("user %q created, ID: %q", user.UserName, user.ID)

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdUserDelete = &cobra.Command{ var cmdUserDelete = &cobra.Command{
@ -57,7 +57,7 @@ func userDelete(cmd *cobra.Command, args []string) error {
log.Info().Msgf("deleting user %q", userDeleteOpts.username) log.Info().Msgf("deleting user %q", userDeleteOpts.username)
if _, err := gwclient.DeleteUser(context.TODO(), userDeleteOpts.username); err != nil { 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 return nil

View File

@ -17,12 +17,12 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdUserLACreate = &cobra.Command{ 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) log.Info().Msgf("creating linked account for user %q", userLACreateOpts.username)
resp, _, err := gwclient.CreateUserLA(context.TODO(), userLACreateOpts.username, req) resp, _, err := gwclient.CreateUserLA(context.TODO(), userLACreateOpts.username, req)
if err != nil { 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 != "" { if resp.Oauth2Redirect != "" {
log.Info().Msgf("visit %s to continue", resp.Oauth2Redirect) log.Info().Msgf("visit %s to continue", resp.Oauth2Redirect)

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdUserLADelete = &cobra.Command{ 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) log.Info().Msgf("deleting linked account %q for user %q", laID, userName)
_, err := gwclient.DeleteUserLA(context.TODO(), userName, laID) _, err := gwclient.DeleteUserLA(context.TODO(), userName, laID)
if err != nil { 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) log.Info().Msgf("linked account %q for user %q deleted", laID, userName)

View File

@ -18,6 +18,7 @@ import (
"context" "context"
"fmt" "fmt"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" 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) users, _, err := gwclient.GetUsers(context.TODO(), userListOpts.start, userListOpts.limit, false)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
printUsers(users) printUsers(users)

View File

@ -18,12 +18,12 @@ import (
"context" "context"
"fmt" "fmt"
"agola.io/agola/internal/errors"
gwapitypes "agola.io/agola/services/gateway/api/types" gwapitypes "agola.io/agola/services/gateway/api/types"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdUserTokenCreate = &cobra.Command{ 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) log.Info().Msgf("creating token for user %q", userTokenCreateOpts.username)
resp, _, err := gwclient.CreateUserToken(context.TODO(), userTokenCreateOpts.username, req) resp, _, err := gwclient.CreateUserToken(context.TODO(), userTokenCreateOpts.username, req)
if err != nil { 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) log.Info().Msgf("token for user %q created: %s", userTokenCreateOpts.username, resp.Token)
fmt.Println(resp.Token) fmt.Println(resp.Token)

View File

@ -17,11 +17,11 @@ package cmd
import ( import (
"context" "context"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
errors "golang.org/x/xerrors"
) )
var cmdUserTokenDelete = &cobra.Command{ 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) log.Info().Msgf("deleting token %q for user %q", tokenName, userName)
_, err := gwclient.DeleteUserToken(context.TODO(), userName, tokenName) _, err := gwclient.DeleteUserToken(context.TODO(), userName, tokenName)
if err != nil { 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) log.Info().Msgf("token %q for user %q deleted", tokenName, userName)

View File

@ -18,6 +18,7 @@ import (
"context" "context"
"fmt" "fmt"
"agola.io/agola/internal/errors"
gwclient "agola.io/agola/services/gateway/client" gwclient "agola.io/agola/services/gateway/client"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -43,7 +44,7 @@ func printVersions(cmd *cobra.Command, args []string) error {
gwversion, _, err := gwclient.GetVersion(context.TODO()) gwversion, _, err := gwclient.GetVersion(context.TODO())
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
fmt.Printf("Gateway version:\t%s\n", gwversion.Version) fmt.Printf("Gateway version:\t%s\n", gwversion.Version)

View File

@ -21,6 +21,7 @@ import (
"log" "log"
"os" "os"
"agola.io/agola/internal/errors"
"github.com/spf13/cobra" "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 // create a temp dir if the image doesn't have one
tmpDir := os.TempDir() tmpDir := os.TempDir()
if err := os.MkdirAll(tmpDir, 0777); err != nil { 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("", "") file, err := ioutil.TempFile("", "")
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
filename := file.Name() filename := file.Name()
if _, err := io.Copy(file, r); err != nil { if _, err := io.Copy(file, r); err != nil {
file.Close() file.Close()
return "", err return "", errors.WithStack(err)
} }
file.Close() file.Close()

View File

@ -17,7 +17,6 @@ package cmd
import ( import (
"crypto/md5" "crypto/md5"
"crypto/sha256" "crypto/sha256"
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -28,6 +27,8 @@ import (
"text/template" "text/template"
"time" "time"
"agola.io/agola/internal/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -48,20 +49,20 @@ func md5sum(filename string) (string, error) {
if info, err := os.Stat(filename); err == nil { if info, err := os.Stat(filename); err == nil {
if info.Size() > 1024*1024 { if info.Size() > 1024*1024 {
return "", fmt.Errorf("file %q is too big", filename) return "", errors.Errorf("file %q is too big", filename)
} }
} else { } else {
return "", err return "", errors.WithStack(err)
} }
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
h := md5.New() h := md5.New()
if _, err := io.Copy(h, f); err != nil { if _, err := io.Copy(h, f); err != nil {
return "", err return "", errors.WithStack(err)
} }
return fmt.Sprintf("%x", h.Sum(nil)), nil 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, err := os.Stat(filename); err == nil {
if info.Size() > 1024*1024 { if info.Size() > 1024*1024 {
return "", fmt.Errorf("file %q is too big", filename) return "", errors.Errorf("file %q is too big", filename)
} }
} else { } else {
return "", err return "", errors.WithStack(err)
} }
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
h := sha256.New() h := sha256.New()
if _, err := io.Copy(h, f); err != nil { if _, err := io.Copy(h, f); err != nil {
return "", err return "", errors.WithStack(err)
} }
return fmt.Sprintf("%x", h.Sum(nil)), nil return fmt.Sprintf("%x", h.Sum(nil)), nil

View File

@ -2,7 +2,7 @@
#### Start the web interface #### 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: 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 ### 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 ./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 ./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.

1
go.mod
View File

@ -35,7 +35,6 @@ require (
go.starlark.net v0.0.0-20200203144150-6677ee5c7211 go.starlark.net v0.0.0-20200203144150-6677ee5c7211
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d 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-billy.v4 v4.3.2
gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v2 v2.2.8 gopkg.in/yaml.v2 v2.2.8

View File

@ -21,12 +21,12 @@ import (
"os" "os"
"path" "path"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/etcd" "agola.io/agola/internal/etcd"
"agola.io/agola/internal/objectstorage" "agola.io/agola/internal/objectstorage"
"agola.io/agola/internal/services/config" "agola.io/agola/internal/services/config"
"github.com/rs/zerolog" "github.com/rs/zerolog"
errors "golang.org/x/xerrors"
) )
const ( const (
@ -43,7 +43,7 @@ func WriteFileAtomicFunc(filename string, perm os.FileMode, writeFunc func(f io.
dir, name := path.Split(filename) dir, name := path.Split(filename)
f, err := ioutil.TempFile(dir, name) f, err := ioutil.TempFile(dir, name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
err = writeFunc(f) err = writeFunc(f)
if err == nil { if err == nil {
@ -62,7 +62,7 @@ func WriteFileAtomicFunc(filename string, perm os.FileMode, writeFunc func(f io.
if err != nil { if err != nil {
os.Remove(f.Name()) os.Remove(f.Name())
} }
return err return errors.WithStack(err)
} }
// WriteFileAtomic atomically writes a file // WriteFileAtomic atomically writes a file
@ -70,7 +70,7 @@ func WriteFileAtomic(filename string, data []byte, perm os.FileMode) error {
return WriteFileAtomicFunc(filename, perm, return WriteFileAtomicFunc(filename, perm,
func(f io.Writer) error { func(f io.Writer) error {
_, err := f.Write(data) _, 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: case config.ObjectStorageTypePosix:
ost, err = objectstorage.NewPosix(c.Path) ost, err = objectstorage.NewPosix(c.Path)
if err != nil { 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: case config.ObjectStorageTypeS3:
// minio golang client doesn't accept an url as an endpoint // 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) ost, err = objectstorage.NewS3(c.Bucket, c.Location, endpoint, c.AccessKey, c.SecretAccessKey, secure)
if err != nil { 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, SkipTLSVerify: c.TLSSkipVerify,
}) })
if err != nil { 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 return e, nil

View File

@ -20,12 +20,12 @@ import (
"regexp" "regexp"
"strings" "strings"
"agola.io/agola/internal/errors"
itypes "agola.io/agola/internal/services/types" itypes "agola.io/agola/internal/services/types"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/types" "agola.io/agola/services/types"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
errors "golang.org/x/xerrors"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
) )
@ -201,7 +201,7 @@ type SaveContent struct {
func (s *Steps) UnmarshalJSON(b []byte) error { func (s *Steps) UnmarshalJSON(b []byte) error {
var stepsRaw []json.RawMessage var stepsRaw []json.RawMessage
if err := json.Unmarshal(b, &stepsRaw); err != nil { if err := json.Unmarshal(b, &stepsRaw); err != nil {
return err return errors.WithStack(err)
} }
steps := make(Steps, len(stepsRaw)) steps := make(Steps, len(stepsRaw))
@ -210,13 +210,13 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
var stepMap map[string]json.RawMessage var stepMap map[string]json.RawMessage
if err := json.Unmarshal(stepRaw, &stepMap); err != nil { 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 } // handle default step definition using format { type: "steptype", other steps fields }
if _, ok := stepMap["type"]; ok { if _, ok := stepMap["type"]; ok {
var stepTypeI interface{} var stepTypeI interface{}
if err := json.Unmarshal(stepMap["type"], &stepTypeI); err != nil { if err := json.Unmarshal(stepMap["type"], &stepTypeI); err != nil {
return err return errors.WithStack(err)
} }
stepType, ok := stepTypeI.(string) stepType, ok := stepTypeI.(string)
if !ok { if !ok {
@ -227,7 +227,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "clone": case "clone":
var s CloneStep var s CloneStep
if err := json.Unmarshal(stepRaw, &s); err != nil { if err := json.Unmarshal(stepRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -235,7 +235,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "run": case "run":
var s RunStep var s RunStep
if err := json.Unmarshal(stepRaw, &s); err != nil { if err := json.Unmarshal(stepRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
if s.Tty == nil { if s.Tty == nil {
s.Tty = util.BoolP(true) s.Tty = util.BoolP(true)
@ -246,7 +246,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "save_to_workspace": case "save_to_workspace":
var s SaveToWorkspaceStep var s SaveToWorkspaceStep
if err := json.Unmarshal(stepRaw, &s); err != nil { if err := json.Unmarshal(stepRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -254,7 +254,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "restore_workspace": case "restore_workspace":
var s RestoreWorkspaceStep var s RestoreWorkspaceStep
if err := json.Unmarshal(stepRaw, &s); err != nil { if err := json.Unmarshal(stepRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -262,7 +262,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "save_cache": case "save_cache":
var s SaveCacheStep var s SaveCacheStep
if err := json.Unmarshal(stepRaw, &s); err != nil { if err := json.Unmarshal(stepRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -270,7 +270,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "restore_cache": case "restore_cache":
var s RestoreCacheStep var s RestoreCacheStep
if err := json.Unmarshal(stepRaw, &s); err != nil { if err := json.Unmarshal(stepRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -285,14 +285,14 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
for stepType, stepSpecRaw := range stepMap { for stepType, stepSpecRaw := range stepMap {
var stepSpec interface{} var stepSpec interface{}
if err := json.Unmarshal(stepSpecRaw, &stepSpec); err != nil { if err := json.Unmarshal(stepSpecRaw, &stepSpec); err != nil {
return err return errors.WithStack(err)
} }
switch stepType { switch stepType {
case "clone": case "clone":
var s CloneStep var s CloneStep
if err := json.Unmarshal(stepSpecRaw, &s); err != nil { if err := json.Unmarshal(stepSpecRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -304,7 +304,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
s.Command = stepSpec s.Command = stepSpec
default: default:
if err := json.Unmarshal(stepSpecRaw, &s); err != nil { if err := json.Unmarshal(stepSpecRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
} }
s.Type = stepType s.Type = stepType
@ -313,7 +313,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "save_to_workspace": case "save_to_workspace":
var s SaveToWorkspaceStep var s SaveToWorkspaceStep
if err := json.Unmarshal(stepSpecRaw, &s); err != nil { if err := json.Unmarshal(stepSpecRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -321,7 +321,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "restore_workspace": case "restore_workspace":
var s RestoreWorkspaceStep var s RestoreWorkspaceStep
if err := json.Unmarshal(stepSpecRaw, &s); err != nil { if err := json.Unmarshal(stepSpecRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -329,7 +329,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "save_cache": case "save_cache":
var s SaveCacheStep var s SaveCacheStep
if err := json.Unmarshal(stepSpecRaw, &s); err != nil { if err := json.Unmarshal(stepSpecRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -337,7 +337,7 @@ func (s *Steps) UnmarshalJSON(b []byte) error {
case "restore_cache": case "restore_cache":
var s RestoreCacheStep var s RestoreCacheStep
if err := json.Unmarshal(stepSpecRaw, &s); err != nil { if err := json.Unmarshal(stepSpecRaw, &s); err != nil {
return err return errors.WithStack(err)
} }
s.Type = stepType s.Type = stepType
step = &s step = &s
@ -359,14 +359,14 @@ func (d *Depends) UnmarshalJSON(b []byte) error {
var dependsRaw []json.RawMessage var dependsRaw []json.RawMessage
if err := json.Unmarshal(b, &dependsRaw); err != nil { if err := json.Unmarshal(b, &dependsRaw); err != nil {
return err return errors.WithStack(err)
} }
depends := make([]*Depend, len(dependsRaw)) depends := make([]*Depend, len(dependsRaw))
for i, dependRaw := range dependsRaw { for i, dependRaw := range dependsRaw {
var dependi interface{} var dependi interface{}
if err := json.Unmarshal(dependRaw, &dependi); err != nil { if err := json.Unmarshal(dependRaw, &dependi); err != nil {
return err return errors.WithStack(err)
} }
var depend *Depend var depend *Depend
isSimpler := false isSimpler := false
@ -391,7 +391,7 @@ func (d *Depends) UnmarshalJSON(b []byte) error {
if !isSimpler { if !isSimpler {
// handle default depends definition using format "task": "taskname", conditions: [ list of conditions ] // handle default depends definition using format "task": "taskname", conditions: [ list of conditions ]
if err := json.Unmarshal(dependRaw, &depend); err != nil { if err := json.Unmarshal(dependRaw, &depend); err != nil {
return err return errors.WithStack(err)
} }
} else { } else {
// handle simpler (for yaml) depends definition using format "taskname": [ list of conditions ] // 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 type deplist map[string][]DependCondition
var dl deplist var dl deplist
if err := json.Unmarshal(dependRaw, &dl); err != nil { if err := json.Unmarshal(dependRaw, &dl); err != nil {
return err return errors.WithStack(err)
} }
if len(dl) != 1 { if len(dl) != 1 {
return errors.Errorf("unsupported depend entry format") return errors.Errorf("unsupported depend entry format")
@ -440,7 +440,7 @@ type Value struct {
func (val *Value) UnmarshalJSON(b []byte) error { func (val *Value) UnmarshalJSON(b []byte) error {
var ival interface{} var ival interface{}
if err := json.Unmarshal(b, &ival); err != nil { if err := json.Unmarshal(b, &ival); err != nil {
return err return errors.WithStack(err)
} }
switch valValue := ival.(type) { switch valValue := ival.(type) {
case string: case string:
@ -479,7 +479,7 @@ func (w *When) ToWhen() *types.When {
func (w *When) UnmarshalJSON(b []byte) error { func (w *When) UnmarshalJSON(b []byte) error {
var wi *when var wi *when
if err := json.Unmarshal(b, &wi); err != nil { if err := json.Unmarshal(b, &wi); err != nil {
return err return errors.WithStack(err)
} }
var err error var err error
@ -487,21 +487,21 @@ func (w *When) UnmarshalJSON(b []byte) error {
if wi.Branch != nil { if wi.Branch != nil {
w.Branch, err = parseWhenConditions(wi.Branch) w.Branch, err = parseWhenConditions(wi.Branch)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
} }
if wi.Tag != nil { if wi.Tag != nil {
w.Tag, err = parseWhenConditions(wi.Tag) w.Tag, err = parseWhenConditions(wi.Tag)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
} }
if wi.Ref != nil { if wi.Ref != nil {
w.Ref, err = parseWhenConditions(wi.Ref) w.Ref, err = parseWhenConditions(wi.Ref)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
} }
@ -521,7 +521,7 @@ func parseWhenConditions(wi interface{}) (*types.WhenConditions, error) {
case []interface{}: case []interface{}:
ss, err := parseSliceString(c) ss, err := parseSliceString(c)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
include = ss include = ss
case map[string]interface{}: case map[string]interface{}:
@ -530,12 +530,12 @@ func parseWhenConditions(wi interface{}) (*types.WhenConditions, error) {
case "include": case "include":
include, err = parseStringOrSlice(v) include, err = parseStringOrSlice(v)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
case "exclude": case "exclude":
exclude, err = parseStringOrSlice(v) exclude, err = parseStringOrSlice(v)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
default: default:
return nil, errors.Errorf(`expected one of "include" or "exclude", got %s`, k) 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) w.Include, err = parseWhenConditionSlice(include)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
w.Exclude, err = parseWhenConditionSlice(exclude) w.Exclude, err = parseWhenConditionSlice(exclude)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return w, nil return w, nil
@ -566,7 +566,7 @@ func parseWhenConditionSlice(conds []string) ([]types.WhenCondition, error) {
for _, cond := range conds { for _, cond := range conds {
wc, err := parseWhenCondition(cond) wc, err := parseWhenCondition(cond)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
wcs = append(wcs, *wc) wcs = append(wcs, *wc)
} }
@ -590,7 +590,7 @@ func parseWhenCondition(s string) (*types.WhenCondition, error) {
if isRegExp { if isRegExp {
if _, err := regexp.Compile(s); err != nil { 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 wc.Type = types.WhenConditionTypeRegExp
} else { } else {
@ -608,7 +608,7 @@ func parseStringOrSlice(si interface{}) ([]string, error) {
var err error var err error
ss, err = parseSliceString(c) ss, err = parseSliceString(c)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
} }
return ss, nil return ss, nil
@ -669,14 +669,14 @@ func ParseConfig(configData []byte, format ConfigFormat, configContext *ConfigCo
var err error var err error
configData, err = execJsonnet(configData, configContext) configData, err = execJsonnet(configData, configContext)
if err != nil { if err != nil {
return nil, errors.Errorf("failed to execute jsonnet: %w", err) return nil, errors.Wrapf(err, "failed to execute jsonnet")
} }
case ConfigFormatStarlark: case ConfigFormatStarlark:
// Generate json from starlark // Generate json from starlark
var err error var err error
configData, err = execStarlark(configData, configContext) configData, err = execStarlark(configData, configContext)
if err != nil { 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 config := DefaultConfig
if err := yaml.Unmarshal(configData, &config); err != nil { 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) return &config, checkConfig(&config)

View File

@ -15,14 +15,13 @@
package config package config
import ( import (
"fmt"
"testing" "testing"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/types" "agola.io/agola/services/types"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
errors "golang.org/x/xerrors"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
) )
@ -35,14 +34,14 @@ func TestParseConfig(t *testing.T) {
{ {
name: "test no runs 1", name: "test no runs 1",
in: ``, in: ``,
err: fmt.Errorf(`no runs defined`), err: errors.Errorf(`no runs defined`),
}, },
{ {
name: "test no runs 2", name: "test no runs 2",
in: ` in: `
runs: runs:
`, `,
err: fmt.Errorf(`no runs defined`), err: errors.Errorf(`no runs defined`),
}, },
{ {
name: "test empty run", name: "test empty run",
@ -50,7 +49,7 @@ func TestParseConfig(t *testing.T) {
runs: runs:
- -
`, `,
err: fmt.Errorf(`run at index 0 is empty`), err: errors.Errorf(`run at index 0 is empty`),
}, },
{ {
name: "test empty task", name: "test empty task",
@ -60,7 +59,7 @@ func TestParseConfig(t *testing.T) {
tasks: 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", name: "test empty runtime arch",
@ -88,7 +87,7 @@ func TestParseConfig(t *testing.T) {
containers: containers:
- image: busybox - 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", name: "test missing task dependency",
@ -104,7 +103,7 @@ func TestParseConfig(t *testing.T) {
depends: depends:
- task02 - 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", name: "test circular dependency between 2 tasks a -> b -> a",

View File

@ -17,21 +17,21 @@ package config
import ( import (
"encoding/json" "encoding/json"
"agola.io/agola/internal/errors"
"github.com/google/go-jsonnet" "github.com/google/go-jsonnet"
errors "golang.org/x/xerrors"
) )
func execJsonnet(configData []byte, configContext *ConfigContext) ([]byte, error) { func execJsonnet(configData []byte, configContext *ConfigContext) ([]byte, error) {
vm := jsonnet.MakeVM() vm := jsonnet.MakeVM()
cj, err := json.Marshal(configContext) cj, err := json.Marshal(configContext)
if err != nil { 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)) vm.TLACode("ctx", string(cj))
out, err := vm.EvaluateSnippet("", string(configData)) out, err := vm.EvaluateSnippet("", string(configData))
if err != nil { 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 return []byte(out), nil

View File

@ -19,29 +19,29 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"agola.io/agola/internal/errors"
"go.starlark.net/starlark" "go.starlark.net/starlark"
errors "golang.org/x/xerrors"
) )
func starlarkArgs(cc *ConfigContext) (starlark.Tuple, error) { func starlarkArgs(cc *ConfigContext) (starlark.Tuple, error) {
d := &starlark.Dict{} d := &starlark.Dict{}
if err := d.SetKey(starlark.String("ref_type"), starlark.String(cc.RefType)); err != nil { 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 { 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 { 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 { 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 { 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 { 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 return []starlark.Value{d}, nil
@ -59,13 +59,13 @@ func starlarkJSON(out *bytes.Buffer, v starlark.Value) error {
case starlark.Int: case starlark.Int:
data, err := json.Marshal(v.BigInt()) data, err := json.Marshal(v.BigInt())
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
out.Write(data) out.Write(data)
case starlark.Float: case starlark.Float:
data, err := json.Marshal(float64(v)) data, err := json.Marshal(float64(v))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
out.Write(data) out.Write(data)
case starlark.String: case starlark.String:
@ -76,7 +76,7 @@ func starlarkJSON(out *bytes.Buffer, v starlark.Value) error {
e := json.NewEncoder(data) e := json.NewEncoder(data)
e.SetEscapeHTML(false) e.SetEscapeHTML(false)
if err := e.Encode(string(v)); err != nil { if err := e.Encode(string(v)); err != nil {
return err return errors.WithStack(err)
} }
// remove final \n introduced by the encoder // remove final \n introduced by the encoder
out.Write(bytes.TrimSuffix(data.Bytes(), []byte("\n"))) out.Write(bytes.TrimSuffix(data.Bytes(), []byte("\n")))
@ -87,7 +87,7 @@ func starlarkJSON(out *bytes.Buffer, v starlark.Value) error {
out.WriteString(", ") out.WriteString(", ")
} }
if err := starlarkJSON(out, v.Index(i)); err != nil { if err := starlarkJSON(out, v.Index(i)); err != nil {
return err return errors.WithStack(err)
} }
} }
out.WriteByte(']') out.WriteByte(']')
@ -98,20 +98,20 @@ func starlarkJSON(out *bytes.Buffer, v starlark.Value) error {
out.WriteString(", ") out.WriteString(", ")
} }
if _, ok := item[0].(starlark.String); !ok { 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 { if err := starlarkJSON(out, item[0]); err != nil {
return err return errors.WithStack(err)
} }
out.WriteString(": ") out.WriteString(": ")
if err := starlarkJSON(out, item[1]); err != nil { if err := starlarkJSON(out, item[1]); err != nil {
return err return errors.WithStack(err)
} }
} }
out.WriteByte('}') out.WriteByte('}')
default: 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 return nil
} }
@ -124,7 +124,7 @@ func execStarlark(configData []byte, configContext *ConfigContext) ([]byte, erro
} }
globals, err := starlark.ExecFile(thread, "config.star", configData, nil) globals, err := starlark.ExecFile(thread, "config.star", configData, nil)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
// we require a main function that will be called wiht one // 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) args, err := starlarkArgs(configContext)
if err != nil { 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) mainVal, err = starlark.Call(thread, main, args, nil)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
switch v := mainVal.(type) { switch v := mainVal.(type) {
case *starlark.Dict: case *starlark.Dict:
if err := starlarkJSON(buf, v); err != nil { if err := starlarkJSON(buf, v); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
default: default:
return nil, errors.Errorf("wrong starlark output, must be a dict") return nil, errors.Errorf("wrong starlark output, must be a dict")

View File

@ -16,10 +16,10 @@ package config
import ( import (
"bytes" "bytes"
"fmt"
"math" "math"
"testing" "testing"
"agola.io/agola/internal/errors"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"go.starlark.net/starlark" "go.starlark.net/starlark"
) )
@ -48,7 +48,7 @@ func TestStarlarkJSON(t *testing.T) {
_ = s.SetKey(starlark.MakeInt(10), starlark.String("string01")) _ = s.SetKey(starlark.MakeInt(10), starlark.String("string01"))
return starlark.Value(s) 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", name: "test list",

View File

@ -24,11 +24,11 @@ import (
"sync" "sync"
"time" "time"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/etcd" "agola.io/agola/internal/etcd"
etcdclientv3rpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" etcdclientv3rpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes"
"go.etcd.io/etcd/mvcc/mvccpb" "go.etcd.io/etcd/mvcc/mvccpb"
errors "golang.org/x/xerrors"
) )
// TODO(sgotti) rewrite this to use a sqlite local cache // 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) walDataFile, err := d.ost.ReadObject(walDataFilePath)
if err != nil { 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() defer walDataFile.Close()
dec := json.NewDecoder(walDataFile) dec := json.NewDecoder(walDataFile)
@ -148,7 +148,7 @@ func (d *DataManager) applyWalChanges(ctx context.Context, walData *WalData, rev
break break
} }
if err != nil { 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) d.applyWalChangesAction(ctx, action, walData.WalSequence, revision)
@ -200,7 +200,7 @@ func (d *DataManager) initializeChanges(ctx context.Context) error {
for { for {
listResp, err := d.e.ListPaged(ctx, etcdWalsDir+"/", 0, 10, continuation) listResp, err := d.e.ListPaged(ctx, etcdWalsDir+"/", 0, 10, continuation)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
resp := listResp.Resp resp := listResp.Resp
continuation = listResp.Continuation continuation = listResp.Continuation
@ -210,10 +210,10 @@ func (d *DataManager) initializeChanges(ctx context.Context) error {
for _, kv := range resp.Kvs { for _, kv := range resp.Kvs {
var walData *WalData var walData *WalData
if err := json.Unmarshal(kv.Value, &walData); err != nil { if err := json.Unmarshal(kv.Value, &walData); err != nil {
return err return errors.WithStack(err)
} }
if err := d.applyWalChanges(ctx, walData, revision); err != nil { if err := d.applyWalChanges(ctx, walData, revision); err != nil {
return err return errors.WithStack(err)
} }
} }
if !listResp.HasMore { if !listResp.HasMore {
@ -226,7 +226,7 @@ func (d *DataManager) initializeChanges(ctx context.Context) error {
for { for {
listResp, err := d.e.ListPaged(ctx, etcdChangeGroupsDir+"/", 0, 10, continuation) listResp, err := d.e.ListPaged(ctx, etcdChangeGroupsDir+"/", 0, 10, continuation)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
resp := listResp.Resp resp := listResp.Resp
continuation = listResp.Continuation continuation = listResp.Continuation
@ -267,7 +267,7 @@ func (d *DataManager) watcher(ctx context.Context) error {
d.changes.initialized = false d.changes.initialized = false
d.changes.Unlock() d.changes.Unlock()
} }
return errors.Errorf("watch error: %w", err) return errors.Wrapf(err, "watch error")
} }
revision := wresp.Header.Revision revision := wresp.Header.Revision
@ -280,13 +280,13 @@ func (d *DataManager) watcher(ctx context.Context) error {
case mvccpb.PUT: case mvccpb.PUT:
var walData *WalData var walData *WalData
if err := json.Unmarshal(ev.Kv.Value, &walData); err != nil { if err := json.Unmarshal(ev.Kv.Value, &walData); err != nil {
return err return errors.WithStack(err)
} }
if walData.WalStatus != WalStatusCommitted { if walData.WalStatus != WalStatusCommitted {
continue continue
} }
if err := d.applyWalChanges(ctx, walData, revision); err != nil { if err := d.applyWalChanges(ctx, walData, revision); err != nil {
return err return errors.WithStack(err)
} }
case mvccpb.DELETE: case mvccpb.DELETE:
walseq := path.Base(string(key)) walseq := path.Base(string(key))

View File

@ -26,11 +26,11 @@ import (
"sort" "sort"
"strings" "strings"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/objectstorage" "agola.io/agola/internal/objectstorage"
"agola.io/agola/internal/sequence" "agola.io/agola/internal/sequence"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
errors "golang.org/x/xerrors"
) )
// ErrNoDataStatus represent when there's no data status files in the ost // 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 { for _, walData := range wals {
header, err := d.ReadWal(walData.WalSequence) header, err := d.ReadWal(walData.WalSequence)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
walFile, err := d.ReadWalData(header.WalDataFileID) walFile, err := d.ReadWalData(header.WalDataFileID)
if err != nil { 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() defer walFile.Close()
@ -115,7 +115,7 @@ func (d *DataManager) walIndex(ctx context.Context, wals []*WalData) (walIndex,
break break
} }
if err != nil { 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 { 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 { func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) error {
dataSequence, err := sequence.IncSequence(ctx, d.e, etcdCheckpointSeqKey) dataSequence, err := sequence.IncSequence(ctx, d.e, etcdCheckpointSeqKey)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
var lastWalSequence string var lastWalSequence string
@ -164,7 +164,7 @@ func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) er
curDataStatus, err := d.GetLastDataStatus() curDataStatus, err := d.GetLastDataStatus()
if err != nil && !errors.Is(err, ErrNoDataStatus) { if err != nil && !errors.Is(err, ErrNoDataStatus) {
return err return errors.WithStack(err)
} }
startWalIndex := 0 startWalIndex := 0
@ -184,7 +184,7 @@ func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) er
wi, err := d.walIndex(ctx, wals) wi, err := d.walIndex(ctx, wals)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
for _, dataType := range d.dataTypes { 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) dataStatusFiles, err := d.writeDataType(ctx, wi, dataType, dataSequence, curDataStatusFiles)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
dataStatus.Files[dataType] = dataStatusFiles dataStatus.Files[dataType] = dataStatusFiles
} }
dataStatusj, err := json.Marshal(dataStatus) dataStatusj, err := json.Marshal(dataStatus)
if err != nil { 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 { if err := d.ost.WriteObject(d.dataStatusPath(dataSequence), bytes.NewReader(dataStatusj), int64(len(dataStatusj)), true); err != nil {
return fromOSTError(err) 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 { func (d *DataManager) writeDataFile(ctx context.Context, buf *bytes.Buffer, size int64, dataFileIndex *DataFileIndex, dataFileID, dataType string) error {
if buf.Len() == 0 { 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 { 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) dataFileIndexj, err := json.Marshal(dataFileIndex)
if err != nil { 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 { if err := d.ost.WriteObject(d.DataFileIndexPath(dataType, dataFileID), bytes.NewReader(dataFileIndexj), int64(len(dataFileIndexj)), true); err != nil {
return fromOSTError(err) return fromOSTError(err)
@ -354,7 +354,7 @@ func (d *DataManager) writeDataType(ctx context.Context, wi walIndex, dataType s
} }
if err != nil { if err != nil {
oldDataf.Close() oldDataf.Close()
return nil, err return nil, errors.WithStack(err)
} }
dataEntries = append(dataEntries, de) dataEntries = append(dataEntries, de)
@ -434,10 +434,10 @@ func (d *DataManager) writeDataType(ctx context.Context, wi walIndex, dataType s
lastEntryID = de.ID lastEntryID = de.ID
dataEntryj, err := json.Marshal(de) dataEntryj, err := json.Marshal(de)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if _, err := buf.Write(dataEntryj); err != nil { if _, err := buf.Write(dataEntryj); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
dataFileIndex.Index[de.ID] = pos - lastSplitPos dataFileIndex.Index[de.ID] = pos - lastSplitPos
prevPos := pos prevPos := pos
@ -470,7 +470,7 @@ func (d *DataManager) writeDataType(ctx context.Context, wi walIndex, dataType s
for i, sp := range splitPoints { for i, sp := range splitPoints {
curDataFileID := d.dataFileID(dataSequence, uuid.Must(uuid.NewV4()).String()) curDataFileID := d.dataFileID(dataSequence, uuid.Must(uuid.NewV4()).String())
if err := d.writeDataFile(ctx, &buf, sp.pos-curPos, dataFileIndexes[i], curDataFileID, dataType); err != nil { 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 // insert new dataStatusFile
dataStatusFiles = append(dataStatusFiles, &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) { func (d *DataManager) Read(dataType, id string) (io.Reader, error) {
curDataStatus, err := d.GetLastDataStatus() curDataStatus, err := d.GetLastDataStatus()
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
curFiles := curDataStatus.Files curFiles := curDataStatus.Files
@ -519,7 +519,7 @@ func (d *DataManager) Read(dataType, id string) (io.Reader, error) {
err = dec.Decode(&dataFileIndex) err = dec.Decode(&dataFileIndex)
if err != nil { if err != nil {
dataFileIndexf.Close() dataFileIndexf.Close()
return nil, err return nil, errors.WithStack(err)
} }
dataFileIndexf.Close() 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 { if _, err := dataf.Seek(int64(pos), io.SeekStart); err != nil {
dataf.Close() dataf.Close()
return nil, err return nil, errors.WithStack(err)
} }
var de *DataEntry var de *DataEntry
dec = json.NewDecoder(dataf) dec = json.NewDecoder(dataf)
if err := dec.Decode(&de); err != nil { if err := dec.Decode(&de); err != nil {
dataf.Close() dataf.Close()
return nil, err return nil, errors.WithStack(err)
} }
dataf.Close() dataf.Close()
@ -640,7 +640,7 @@ func (d *DataManager) GetDataStatus(dataSequence *sequence.Sequence) (*DataStatu
func (d *DataManager) GetFirstDataStatusSequence() (*sequence.Sequence, error) { func (d *DataManager) GetFirstDataStatusSequence() (*sequence.Sequence, error) {
dataStatusSequences, err := d.GetFirstDataStatusSequences(1) dataStatusSequences, err := d.GetFirstDataStatusSequences(1)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return dataStatusSequences[0], nil return dataStatusSequences[0], nil
@ -649,7 +649,7 @@ func (d *DataManager) GetFirstDataStatusSequence() (*sequence.Sequence, error) {
func (d *DataManager) GetLastDataStatusSequence() (*sequence.Sequence, error) { func (d *DataManager) GetLastDataStatusSequence() (*sequence.Sequence, error) {
dataStatusSequences, err := d.GetLastDataStatusSequences(1) dataStatusSequences, err := d.GetLastDataStatusSequences(1)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return dataStatusSequences[0], nil return dataStatusSequences[0], nil
@ -658,7 +658,7 @@ func (d *DataManager) GetLastDataStatusSequence() (*sequence.Sequence, error) {
func (d *DataManager) GetFirstDataStatus() (*DataStatus, error) { func (d *DataManager) GetFirstDataStatus() (*DataStatus, error) {
dataStatusSequence, err := d.GetFirstDataStatusSequence() dataStatusSequence, err := d.GetFirstDataStatusSequence()
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return d.GetDataStatus(dataStatusSequence) return d.GetDataStatus(dataStatusSequence)
@ -667,7 +667,7 @@ func (d *DataManager) GetFirstDataStatus() (*DataStatus, error) {
func (d *DataManager) GetLastDataStatus() (*DataStatus, error) { func (d *DataManager) GetLastDataStatus() (*DataStatus, error) {
dataStatusSequence, err := d.GetLastDataStatusSequence() dataStatusSequence, err := d.GetLastDataStatusSequence()
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return d.GetDataStatus(dataStatusSequence) 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 { func (d *DataManager) Export(ctx context.Context, w io.Writer) error {
if err := d.checkpoint(ctx, true); err != nil { if err := d.checkpoint(ctx, true); err != nil {
return err return errors.WithStack(err)
} }
curDataStatus, err := d.GetLastDataStatus() curDataStatus, err := d.GetLastDataStatus()
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
for _, dataType := range d.dataTypes { 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 { if _, err := io.Copy(w, dataf); err != nil {
dataf.Close() dataf.Close()
return err return errors.WithStack(err)
} }
dataf.Close() 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 { func (d *DataManager) Import(ctx context.Context, r io.Reader) error {
// delete contents in etcd // delete contents in etcd
if err := d.deleteEtcd(ctx); err != nil { if err := d.deleteEtcd(ctx); err != nil {
return err return errors.WithStack(err)
} }
// we require all entries of the same datatypes grouped together // 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 // create a new sequence, we assume that it'll be greater than previous data sequences
dataSequence, err := sequence.IncSequence(ctx, d.e, etcdCheckpointSeqKey) dataSequence, err := sequence.IncSequence(ctx, d.e, etcdCheckpointSeqKey)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
dataStatus := &DataStatus{ dataStatus := &DataStatus{
@ -745,7 +745,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error {
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
dataFileID := d.dataFileID(dataSequence, uuid.Must(uuid.NewV4()).String()) dataFileID := d.dataFileID(dataSequence, uuid.Must(uuid.NewV4()).String())
if err := d.writeDataFile(ctx, &buf, int64(buf.Len()), dataFileIndex, dataFileID, curDataType); err != nil { if err := d.writeDataFile(ctx, &buf, int64(buf.Len()), dataFileIndex, dataFileID, curDataType); err != nil {
return err return errors.WithStack(err)
} }
dataStatusFiles = append(dataStatusFiles, &DataStatusFile{ dataStatusFiles = append(dataStatusFiles, &DataStatusFile{
@ -779,7 +779,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error {
if mustWrite { if mustWrite {
dataFileID := d.dataFileID(dataSequence, uuid.Must(uuid.NewV4()).String()) dataFileID := d.dataFileID(dataSequence, uuid.Must(uuid.NewV4()).String())
if err := d.writeDataFile(ctx, &buf, int64(buf.Len()), dataFileIndex, dataFileID, curDataType); err != nil { if err := d.writeDataFile(ctx, &buf, int64(buf.Len()), dataFileIndex, dataFileID, curDataType); err != nil {
return err return errors.WithStack(err)
} }
dataStatusFiles = append(dataStatusFiles, &DataStatusFile{ dataStatusFiles = append(dataStatusFiles, &DataStatusFile{
@ -810,10 +810,10 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error {
dataEntryj, err := json.Marshal(de) dataEntryj, err := json.Marshal(de)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if _, err := buf.Write(dataEntryj); err != nil { if _, err := buf.Write(dataEntryj); err != nil {
return err return errors.WithStack(err)
} }
dataFileIndex.Index[de.ID] = pos dataFileIndex.Index[de.ID] = pos
pos += int64(len(dataEntryj)) pos += int64(len(dataEntryj))
@ -821,7 +821,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error {
dataStatusj, err := json.Marshal(dataStatus) dataStatusj, err := json.Marshal(dataStatus)
if err != nil { 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 { if err := d.ost.WriteObject(d.dataStatusPath(dataSequence), bytes.NewReader(dataStatusj), int64(len(dataStatusj)), true); err != nil {
return fromOSTError(err) return fromOSTError(err)
@ -829,7 +829,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error {
// initialize etcd providing the specific datastatus // initialize etcd providing the specific datastatus
if err := d.InitEtcd(ctx, dataStatus); err != nil { if err := d.InitEtcd(ctx, dataStatus); err != nil {
return err return errors.WithStack(err)
} }
return nil 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 { func (d *DataManager) CleanOldCheckpoints(ctx context.Context) error {
dataStatusSequences, err := d.GetLastDataStatusSequences(dataStatusToKeep) dataStatusSequences, err := d.GetLastDataStatusSequences(dataStatusToKeep)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return d.cleanOldCheckpoints(ctx, dataStatusSequences) return d.cleanOldCheckpoints(ctx, dataStatusSequences)
@ -894,7 +894,7 @@ func (d *DataManager) cleanOldCheckpoints(ctx context.Context, dataStatusSequenc
for _, dataStatusSequence := range dataStatusSequences { for _, dataStatusSequence := range dataStatusSequences {
dataStatus, err := d.GetDataStatus(dataStatusSequence) dataStatus, err := d.GetDataStatus(dataStatusSequence)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
for dataType := range dataStatus.Files { for dataType := range dataStatus.Files {

View File

@ -21,12 +21,12 @@ import (
"strings" "strings"
"time" "time"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/etcd" "agola.io/agola/internal/etcd"
"agola.io/agola/internal/objectstorage" "agola.io/agola/internal/objectstorage"
"agola.io/agola/internal/sequence" "agola.io/agola/internal/sequence"
"github.com/rs/zerolog" "github.com/rs/zerolog"
errors "golang.org/x/xerrors"
) )
// TODO(sgotti) handle etcd unwanted changes: // TODO(sgotti) handle etcd unwanted changes:
@ -252,7 +252,7 @@ func (d *DataManager) deleteEtcd(ctx context.Context) error {
} }
for _, prefix := range prefixes { for _, prefix := range prefixes {
if err := d.e.DeletePrefix(ctx, prefix); err != nil { if err := d.e.DeletePrefix(ctx, prefix); err != nil {
return err return errors.WithStack(err)
} }
} }

View File

@ -29,12 +29,12 @@ import (
"testing" "testing"
"time" "time"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/objectstorage" "agola.io/agola/internal/objectstorage"
"agola.io/agola/internal/testutil" "agola.io/agola/internal/testutil"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/rs/zerolog" "github.com/rs/zerolog"
errors "golang.org/x/xerrors"
) )
func setupEtcd(t *testing.T, log zerolog.Logger, dir string) *testutil.TestEmbeddedEtcd { 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 // populate with a wal
_, err := dm.WriteWal(ctx, actionGroup, nil) _, err := dm.WriteWal(ctx, actionGroup, nil)
if err != 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 // do a checkpoint
if err := dm.checkpoint(ctx, true); err != nil { 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 { if err := checkDataFiles(ctx, t, dm, expectedEntries); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return expectedEntries, nil return expectedEntries, nil
@ -635,7 +635,7 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected
// read the data file // read the data file
curDataStatus, err := dm.GetLastDataStatus() curDataStatus, err := dm.GetLastDataStatus()
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
allEntriesMap := map[string]*DataEntry{} 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] { for i, file := range curDataStatus.Files[dataType] {
dataFileIndexf, err := dm.ost.ReadObject(dm.DataFileIndexPath(dataType, file.ID)) dataFileIndexf, err := dm.ost.ReadObject(dm.DataFileIndexPath(dataType, file.ID))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
var dataFileIndex *DataFileIndex var dataFileIndex *DataFileIndex
dec := json.NewDecoder(dataFileIndexf) dec := json.NewDecoder(dataFileIndexf)
err = dec.Decode(&dataFileIndex) err = dec.Decode(&dataFileIndex)
if err != nil { if err != nil {
dataFileIndexf.Close() dataFileIndexf.Close()
return err return errors.WithStack(err)
} }
dataFileIndexf.Close() dataFileIndexf.Close()
@ -660,7 +660,7 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected
dataEntries := []*DataEntry{} dataEntries := []*DataEntry{}
dataf, err := dm.ost.ReadObject(dm.DataFilePath(dataType, file.ID)) dataf, err := dm.ost.ReadObject(dm.DataFilePath(dataType, file.ID))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
dec = json.NewDecoder(dataf) dec = json.NewDecoder(dataf)
var prevEntryID string var prevEntryID string
@ -674,15 +674,15 @@ func checkDataFiles(ctx context.Context, t *testing.T, dm *DataManager, expected
} }
if err != nil { if err != nil {
dataf.Close() dataf.Close()
return err return errors.WithStack(err)
} }
// check that there are no duplicate entries // check that there are no duplicate entries
if _, ok := allEntriesMap[de.ID]; ok { 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 // check that the entries are in order
if de.ID < prevEntryID { 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 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 // check that the index matches the entries
if len(dataFileIndex.Index) != len(dataEntriesMap) { 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)) indexIDs := make([]string, len(dataFileIndex.Index))
entriesIDs := make([]string, len(dataEntriesMap)) 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(indexIDs)
sort.Strings(entriesIDs) sort.Strings(entriesIDs)
if !reflect.DeepEqual(indexIDs, 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 { 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 // check that all the files are in order
if file.LastEntryID == prevLastEntryID { 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 { 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 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 // check that the number of entries is right
if len(allEntriesMap) != len(expectedEntriesMap) { 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) { 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 return nil

View File

@ -25,6 +25,7 @@ import (
"strings" "strings"
"time" "time"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/etcd" "agola.io/agola/internal/etcd"
"agola.io/agola/internal/objectstorage" "agola.io/agola/internal/objectstorage"
"agola.io/agola/internal/sequence" "agola.io/agola/internal/sequence"
@ -34,7 +35,6 @@ import (
"go.etcd.io/etcd/clientv3/concurrency" "go.etcd.io/etcd/clientv3/concurrency"
etcdclientv3rpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" etcdclientv3rpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes"
"go.etcd.io/etcd/mvcc/mvccpb" "go.etcd.io/etcd/mvcc/mvccpb"
errors "golang.org/x/xerrors"
) )
type ActionType string type ActionType string
@ -127,7 +127,7 @@ func (d *DataManager) ReadObject(dataType, id string, cgNames []string) (io.Read
} }
f, err := d.Read(dataType, id) 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) { func (d *DataManager) HasOSTWal(walseq string) (bool, error) {
@ -150,7 +150,7 @@ func (d *DataManager) ReadWal(walseq string) (*WalHeader, error) {
dec := json.NewDecoder(walFilef) dec := json.NewDecoder(walFilef)
var header *WalHeader var header *WalHeader
if err = dec.Decode(&header); err != nil { if err = dec.Decode(&header); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return header, nil return header, nil
@ -260,7 +260,7 @@ func (d *DataManager) ListEtcdChangeGroups(ctx context.Context, revision int64)
changeGroupsRevisions := changeGroupsRevisions{} changeGroupsRevisions := changeGroupsRevisions{}
resp, err := d.e.List(ctx, etcdChangeGroupsDir, "", revision) resp, err := d.e.List(ctx, etcdChangeGroupsDir, "", revision)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
for _, kv := range resp.Kvs { for _, kv := range resp.Kvs {
changegroupID := path.Base(string(kv.Key)) 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 // list waldata and just get the first if available
listResp, err := d.e.ListPaged(ctx, etcdWalsDir, 0, 1, nil) listResp, err := d.e.ListPaged(ctx, etcdWalsDir, 0, 1, nil)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, errors.WithStack(err)
} }
resp := listResp.Resp resp := listResp.Resp
revision := resp.Header.Revision revision := resp.Header.Revision
@ -288,7 +288,7 @@ func (d *DataManager) FirstAvailableWalData(ctx context.Context) (*WalData, int6
var walData *WalData var walData *WalData
if err := json.Unmarshal(resp.Kvs[0].Value, &walData); err != nil { 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 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) { func (d *DataManager) LastCommittedStorageWal(ctx context.Context) (string, int64, error) {
resp, err := d.e.Get(ctx, etcdLastCommittedStorageWalSeqKey, 0) resp, err := d.e.Get(ctx, etcdLastCommittedStorageWalSeqKey, 0)
if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) {
return "", 0, err return "", 0, errors.WithStack(err)
} }
if errors.Is(err, etcd.ErrKeyNotFound) { if errors.Is(err, etcd.ErrKeyNotFound) {
return "", 0, errors.Errorf("no last committedstorage wal on etcd") 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) walSequence, err := sequence.IncSequence(ctx, d.e, etcdWalSeqKey)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
resp, err := d.e.Get(ctx, etcdWalsDataKey, 0) resp, err := d.e.Get(ctx, etcdWalsDataKey, 0)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var walsData WalsData var walsData WalsData
if err := json.Unmarshal(resp.Kvs[0].Value, &walsData); err != nil { 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 walsData.Revision = resp.Kvs[0].ModRevision
@ -446,10 +446,10 @@ func (d *DataManager) WriteWalAdditionalOps(ctx context.Context, actions []*Acti
for _, action := range actions { for _, action := range actions {
actionj, err := json.Marshal(action) actionj, err := json.Marshal(action)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if _, err := buf.Write(actionj); err != nil { 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 { 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) walsDataj, err := json.Marshal(walsData)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
walDataj, err := json.Marshal(walData) walDataj, err := json.Marshal(walData)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if cmp == nil { 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) txn := d.e.Client().Txn(ctx).If(cmp...).Then(then...).Else(getWalsData, getWal)
tresp, err := txn.Commit() tresp, err := txn.Commit()
if err != nil { if err != nil {
return nil, etcd.FromEtcdError(err) return nil, errors.WithStack(etcd.FromEtcdError(err))
} }
if !tresp.Succeeded { if !tresp.Succeeded {
walsDataRev := tresp.Responses[0].GetResponseRange().Kvs[0].ModRevision 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 { func (d *DataManager) sync(ctx context.Context) error {
session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer session.Close() defer session.Close()
@ -569,18 +569,18 @@ func (d *DataManager) sync(ctx context.Context) error {
if errors.Is(err, etcd.ErrLocked) { if errors.Is(err, etcd.ErrLocked) {
return nil return nil
} }
return err return errors.WithStack(err)
} }
defer func() { _ = m.Unlock(ctx) }() defer func() { _ = m.Unlock(ctx) }()
resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0) resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
for _, kv := range resp.Kvs { for _, kv := range resp.Kvs {
var walData WalData var walData WalData
if err := json.Unmarshal(kv.Value, &walData); err != nil { if err := json.Unmarshal(kv.Value, &walData); err != nil {
return err return errors.WithStack(err)
} }
// wals must be committed and checkpointed in order. // 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 // 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) headerj, err := json.Marshal(header)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
walFileCommittedPath := walFilePath + ".committed" walFileCommittedPath := walFilePath + ".committed"
@ -606,7 +606,7 @@ func (d *DataManager) sync(ctx context.Context) error {
walData.WalStatus = WalStatusCommittedStorage walData.WalStatus = WalStatusCommittedStorage
walDataj, err := json.Marshal(walData) walDataj, err := json.Marshal(walData)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
cmp := []etcdclientv3.Cmp{} 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...) txn := d.e.Client().Txn(ctx).If(cmp...).Then(then...)
tresp, err := txn.Commit() tresp, err := txn.Commit()
if err != nil { if err != nil {
return etcd.FromEtcdError(err) return errors.WithStack(etcd.FromEtcdError(err))
} }
if !tresp.Succeeded { if !tresp.Succeeded {
return errors.Errorf("failed to write committedstorage wal: concurrent update") 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 { func (d *DataManager) checkpoint(ctx context.Context, force bool) error {
session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer session.Close() defer session.Close()
@ -658,19 +658,19 @@ func (d *DataManager) checkpoint(ctx context.Context, force bool) error {
if errors.Is(err, etcd.ErrLocked) { if errors.Is(err, etcd.ErrLocked) {
return nil return nil
} }
return err return errors.WithStack(err)
} }
defer func() { _ = m.Unlock(ctx) }() defer func() { _ = m.Unlock(ctx) }()
resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0) resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
walsData := []*WalData{} walsData := []*WalData{}
for _, kv := range resp.Kvs { for _, kv := range resp.Kvs {
var walData *WalData var walData *WalData
if err := json.Unmarshal(kv.Value, &walData); err != nil { if err := json.Unmarshal(kv.Value, &walData); err != nil {
return err return errors.WithStack(err)
} }
walData.Revision = kv.ModRevision 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 { 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 { for _, walData := range walsData {
@ -700,11 +700,11 @@ func (d *DataManager) checkpoint(ctx context.Context, force bool) error {
walData.WalStatus = WalStatusCheckpointed walData.WalStatus = WalStatusCheckpointed
walDataj, err := json.Marshal(walData) walDataj, err := json.Marshal(walData)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
walKey := etcdWalKey(walData.WalSequence) walKey := etcdWalKey(walData.WalSequence)
if _, err := d.e.AtomicPut(ctx, walKey, walDataj, walData.Revision, nil); err != nil { 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 { func (d *DataManager) checkpointClean(ctx context.Context) error {
session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer session.Close() defer session.Close()
@ -740,12 +740,12 @@ func (d *DataManager) checkpointClean(ctx context.Context) error {
if errors.Is(err, etcd.ErrLocked) { if errors.Is(err, etcd.ErrLocked) {
return nil return nil
} }
return err return errors.WithStack(err)
} }
defer func() { _ = m.Unlock(ctx) }() defer func() { _ = m.Unlock(ctx) }()
if err := d.CleanOldCheckpoints(ctx); err != nil { if err := d.CleanOldCheckpoints(ctx); err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
@ -773,7 +773,7 @@ func (d *DataManager) etcdWalCleanerLoop(ctx context.Context) {
func (d *DataManager) etcdWalCleaner(ctx context.Context) error { func (d *DataManager) etcdWalCleaner(ctx context.Context) error {
session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer session.Close() defer session.Close()
@ -783,13 +783,13 @@ func (d *DataManager) etcdWalCleaner(ctx context.Context) error {
if errors.Is(err, etcd.ErrLocked) { if errors.Is(err, etcd.ErrLocked) {
return nil return nil
} }
return err return errors.WithStack(err)
} }
defer func() { _ = m.Unlock(ctx) }() defer func() { _ = m.Unlock(ctx) }()
resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0) resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if len(resp.Kvs) <= d.etcdWalsKeepNum { if len(resp.Kvs) <= d.etcdWalsKeepNum {
return nil return nil
@ -799,7 +799,7 @@ func (d *DataManager) etcdWalCleaner(ctx context.Context) error {
for _, kv := range resp.Kvs { for _, kv := range resp.Kvs {
var walData WalData var walData WalData
if err := json.Unmarshal(kv.Value, &walData); err != nil { if err := json.Unmarshal(kv.Value, &walData); err != nil {
return err return errors.WithStack(err)
} }
if walData.WalStatus != WalStatusCheckpointed { if walData.WalStatus != WalStatusCheckpointed {
break 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? // arrive to a differnt S3 server that is not yet in sync?
d.log.Info().Msgf("removing wal %q from etcd", walData.WalSequence) d.log.Info().Msgf("removing wal %q from etcd", walData.WalSequence)
if _, err := d.e.AtomicDelete(ctx, string(kv.Key), kv.ModRevision); err != nil { if _, err := d.e.AtomicDelete(ctx, string(kv.Key), kv.ModRevision); err != nil {
return err return errors.WithStack(err)
} }
removeCount-- removeCount--
@ -846,7 +846,7 @@ func (d *DataManager) storageWalCleanerLoop(ctx context.Context) {
func (d *DataManager) storageWalCleaner(ctx context.Context) error { func (d *DataManager) storageWalCleaner(ctx context.Context) error {
session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer session.Close() defer session.Close()
@ -856,13 +856,13 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error {
if errors.Is(err, etcd.ErrLocked) { if errors.Is(err, etcd.ErrLocked) {
return nil return nil
} }
return err return errors.WithStack(err)
} }
defer func() { _ = m.Unlock(ctx) }() defer func() { _ = m.Unlock(ctx) }()
firstDataStatus, err := d.GetFirstDataStatus() firstDataStatus, err := d.GetFirstDataStatus()
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
firstWalSequence := firstDataStatus.WalSequence 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 // it's lesser than the first data status wal sequence
resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0) resp, err := d.e.List(ctx, etcdWalsDir+"/", "", 0)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if len(resp.Kvs) == 0 { if len(resp.Kvs) == 0 {
return errors.Errorf("no wals in etcd") return errors.Errorf("no wals in etcd")
} }
var walData WalData var walData WalData
if err := json.Unmarshal(resp.Kvs[0].Value, &walData); err != nil { if err := json.Unmarshal(resp.Kvs[0].Value, &walData); err != nil {
return err return errors.WithStack(err)
} }
if walData.WalSequence < firstWalSequence { if walData.WalSequence < firstWalSequence {
firstWalSequence = walData.WalSequence firstWalSequence = walData.WalSequence
@ -902,7 +902,7 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error {
header, err := d.ReadWal(walSequence) header, err := d.ReadWal(walSequence)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// first remove wal data file // first remove wal data file
@ -956,7 +956,7 @@ func (d *DataManager) compactChangeGroupsLoop(ctx context.Context) {
func (d *DataManager) compactChangeGroups(ctx context.Context) error { func (d *DataManager) compactChangeGroups(ctx context.Context) error {
session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx)) session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer session.Close() defer session.Close()
@ -966,13 +966,13 @@ func (d *DataManager) compactChangeGroups(ctx context.Context) error {
if errors.Is(err, etcd.ErrLocked) { if errors.Is(err, etcd.ErrLocked) {
return nil return nil
} }
return err return errors.WithStack(err)
} }
defer func() { _ = m.Unlock(ctx) }() defer func() { _ = m.Unlock(ctx) }()
resp, err := d.e.Client().Get(ctx, etcdChangeGroupMinRevisionKey) resp, err := d.e.Client().Get(ctx, etcdChangeGroupMinRevisionKey)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if len(resp.Kvs) == 0 { 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) txn := d.e.Client().Txn(ctx).If(cmp).Then(then)
tresp, err := txn.Commit() tresp, err := txn.Commit()
if err != nil { if err != nil {
return etcd.FromEtcdError(err) return errors.WithStack(etcd.FromEtcdError(err))
} }
if !tresp.Succeeded { if !tresp.Succeeded {
return errors.Errorf("failed to update change group min revision key due to concurrent update") 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 // then remove all the groups keys with modrevision < minrevision
resp, err = d.e.List(ctx, etcdChangeGroupsDir, "", 0) resp, err = d.e.List(ctx, etcdChangeGroupsDir, "", 0)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
for _, kv := range resp.Kvs { for _, kv := range resp.Kvs {
if kv.ModRevision < revision-etcdChangeGroupMinRevisionRange { 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) txn := d.e.Client().Txn(ctx).If(cmp).Then(then)
tresp, err := txn.Commit() tresp, err := txn.Commit()
if err != nil { if err != nil {
return etcd.FromEtcdError(err) return errors.WithStack(etcd.FromEtcdError(err))
} }
if !tresp.Succeeded { if !tresp.Succeeded {
d.log.Err(err).Msgf("failed to update change group min revision key due to concurrent update") 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 { func (d *DataManager) etcdPinger(ctx context.Context) error {
if _, err := d.e.Put(ctx, etcdPingKey, []byte{}, nil); err != nil { if _, err := d.e.Put(ctx, etcdPingKey, []byte{}, nil); err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
} }
@ -1055,7 +1056,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro
var header *WalHeader var header *WalHeader
if err = dec.Decode(&header); err != nil && !errors.Is(err, io.EOF) { if err = dec.Decode(&header); err != nil && !errors.Is(err, io.EOF) {
walFile.Close() walFile.Close()
return err return errors.WithStack(err)
} }
walFile.Close() walFile.Close()
@ -1073,7 +1074,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro
} }
walDataj, err := json.Marshal(walData) walDataj, err := json.Marshal(walData)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
cmp := []etcdclientv3.Cmp{} 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...) txn := d.e.Client().Txn(ctx).If(cmp...).Then(then...)
tresp, err := txn.Commit() tresp, err := txn.Commit()
if err != nil { if err != nil {
return etcd.FromEtcdError(err) return errors.WithStack(etcd.FromEtcdError(err))
} }
if !tresp.Succeeded { if !tresp.Succeeded {
return errors.Errorf("failed to sync etcd: wal %q already written", wal.WalSequence) 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)) session, err := concurrency.NewSession(d.e.Client(), concurrency.WithTTL(5), concurrency.WithContext(ctx))
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer session.Close() defer session.Close()
@ -1104,7 +1105,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro
if errors.Is(err, etcd.ErrLocked) { if errors.Is(err, etcd.ErrLocked) {
return nil return nil
} }
return err return errors.WithStack(err)
} }
defer func() { _ = m.Unlock(ctx) }() 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) _, err = d.e.Get(ctx, etcdWalsDataKey, 0)
if err != nil { if err != nil {
if !errors.Is(err, etcd.ErrKeyNotFound) { if !errors.Is(err, etcd.ErrKeyNotFound) {
return err return errors.WithStack(err)
} }
mustInit = true mustInit = true
} }
@ -1123,7 +1124,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro
// delete all wals from etcd // delete all wals from etcd
if err := d.deleteEtcd(ctx); err != nil { 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, "")) then = append(then, etcdclientv3.OpPut(etcdChangeGroupMinRevisionKey, ""))
txn := d.e.Client().Txn(ctx).If(cmp...).Then(then...) txn := d.e.Client().Txn(ctx).If(cmp...).Then(then...)
if _, err := txn.Commit(); err != nil { if _, err := txn.Commit(); err != nil {
return etcd.FromEtcdError(err) return errors.WithStack(etcd.FromEtcdError(err))
} }
if !mustInit { if !mustInit {
@ -1150,7 +1151,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro
} else { } else {
dataStatus, err = d.GetLastDataStatus() dataStatus, err = d.GetLastDataStatus()
if err != nil && !errors.Is(err, ErrNoDataStatus) { 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 // 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) // 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) d.log.Debug().Msgf("wal: %s", wal)
if wal.Err != nil { if wal.Err != nil {
return wal.Err return errors.WithStack(wal.Err)
} }
if wal.WalSequence < firstWal { if wal.WalSequence < firstWal {
@ -1182,7 +1183,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro
lastCommittedStorageWalSequence = wal.WalSequence lastCommittedStorageWalSequence = wal.WalSequence
if err := writeWal(wal, previousWalSequence); err != nil { if err := writeWal(wal, previousWalSequence); err != nil {
return err return errors.WithStack(err)
} }
previousWalSequence = wal.WalSequence previousWalSequence = wal.WalSequence
wroteWals++ wroteWals++
@ -1192,7 +1193,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro
// insert an empty wal and make it already committedstorage // insert an empty wal and make it already committedstorage
walSequence, err := sequence.IncSequence(ctx, d.e, etcdWalSeqKey) walSequence, err := sequence.IncSequence(ctx, d.e, etcdWalSeqKey)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
walDataFileID := uuid.Must(uuid.NewV4()).String() 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) headerj, err := json.Marshal(header)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
walFileCommittedPath := walFilePath + ".committed" walFileCommittedPath := walFilePath + ".committed"
if err := d.ost.WriteObject(walFileCommittedPath, bytes.NewReader(headerj), int64(len(headerj)), true); err != nil { 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) walDataj, err := json.Marshal(walData)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
walsDataj, err := json.Marshal(walsData) walsDataj, err := json.Marshal(walsData)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// save walsdata and lastcommittedstoragewalseq only after writing all the // 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...) txn = d.e.Client().Txn(ctx).If(cmp...).Then(then...)
tresp, err := txn.Commit() tresp, err := txn.Commit()
if err != nil { if err != nil {
return etcd.FromEtcdError(err) return errors.WithStack(etcd.FromEtcdError(err))
} }
if !tresp.Succeeded { if !tresp.Succeeded {
return errors.Errorf("failed to sync etcd: walsdata already written") 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 // force a checkpoint
if err := d.checkpoint(ctx, true); err != nil { if err := d.checkpoint(ctx, true); err != nil {
return err return errors.WithStack(err)
} }
return nil return nil

View File

@ -18,8 +18,8 @@ import (
"context" "context"
"database/sql" "database/sql"
"agola.io/agola/internal/errors"
sq "github.com/Masterminds/squirrel" sq "github.com/Masterminds/squirrel"
errors "golang.org/x/xerrors"
) )
const dbVersionTableDDLTmpl = ` const dbVersionTableDDLTmpl = `
@ -33,22 +33,22 @@ func (db *DB) Create(ctx context.Context, stmts []string) error {
err := db.Do(ctx, func(tx *Tx) error { err := db.Do(ctx, func(tx *Tx) error {
if _, err := tx.Exec(dbVersionTableDDLTmpl); err != nil { 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 return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
err = db.Do(ctx, func(tx *Tx) error { err = db.Do(ctx, func(tx *Tx) error {
var version sql.NullInt64 var version sql.NullInt64
q, args, err := sb.Select("max(version)").From("dbversion").ToSql() q, args, err := sb.Select("max(version)").From("dbversion").ToSql()
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if err := tx.QueryRow(q, args...).Scan(&version); err != nil { 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 { if version.Valid {
return nil return nil
@ -56,18 +56,18 @@ func (db *DB) Create(ctx context.Context, stmts []string) error {
for _, stmt := range stmts { for _, stmt := range stmts {
if _, err := tx.Exec(stmt); err != nil { 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() q, args, err = sb.Insert("dbversion").Columns("version", "time").Values(dbVersion, "now()").ToSql()
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if _, err := tx.Exec(q, args...); err != nil { 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 nil
}) })
return err return errors.WithStack(err)
} }

View File

@ -20,8 +20,8 @@ import (
"regexp" "regexp"
"time" "time"
"agola.io/agola/internal/errors"
"github.com/mattn/go-sqlite3" "github.com/mattn/go-sqlite3"
errors "golang.org/x/xerrors"
) )
type Type string type Type string
@ -128,7 +128,7 @@ func NewDB(dbType Type, dbConnString string) (*DB, error) {
sqldb, err := sql.Open(driverName, dbConnString) sqldb, err := sql.Open(driverName, dbConnString)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
db := &DB{ db := &DB{
@ -151,11 +151,12 @@ type Tx struct {
} }
func (db *DB) Close() error { 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) { 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 { func (db *DB) NewUnstartedTx() *Tx {
@ -167,7 +168,7 @@ func (db *DB) NewUnstartedTx() *Tx {
func (db *DB) NewTx(ctx context.Context) (*Tx, error) { func (db *DB) NewTx(ctx context.Context) (*Tx, error) {
tx := db.NewUnstartedTx() tx := db.NewUnstartedTx()
if err := tx.Start(ctx); err != nil { if err := tx.Start(ctx); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return tx, nil 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 { func (db *DB) do(ctx context.Context, f func(tx *Tx) error) error {
tx, err := db.NewTx(ctx) tx, err := db.NewTx(ctx)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer func() { defer func() {
if p := recover(); p != nil { 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 { if err = f(tx); err != nil {
_ = tx.Rollback() _ = tx.Rollback()
return err return errors.WithStack(err)
} }
return tx.Commit() 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 { func (tx *Tx) Start(ctx context.Context) error {
wtx, err := tx.db.db.Begin() wtx, err := tx.db.db.Begin()
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
switch tx.db.data.t { switch tx.db.data.t {
case Postgres: case Postgres:
if _, err := wtx.Exec("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"); err != nil { if _, err := wtx.Exec("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"); err != nil {
return err return errors.WithStack(err)
} }
} }
tx.tx = wtx tx.tx = wtx
@ -230,26 +231,26 @@ func (tx *Tx) Commit() error {
if tx.tx == nil { if tx.tx == nil {
return nil return nil
} }
return tx.tx.Commit() return errors.WithStack(tx.tx.Commit())
} }
func (tx *Tx) Rollback() error { func (tx *Tx) Rollback() error {
if tx.tx == nil { if tx.tx == nil {
return nil return nil
} }
return tx.tx.Rollback() return errors.WithStack(tx.tx.Rollback())
} }
func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error) { func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error) {
query = tx.db.data.translate(query) query = tx.db.data.translate(query)
r, err := tx.tx.ExecContext(tx.ctx, query, tx.db.data.translateArgs(args)...) 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) { func (tx *Tx) Query(query string, args ...interface{}) (*sql.Rows, error) {
query = tx.db.data.translate(query) query = tx.db.data.translate(query)
r, err := tx.tx.QueryContext(tx.ctx, query, tx.db.data.translateArgs(args)...) 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 { func (tx *Tx) QueryRow(query string, args ...interface{}) *sql.Row {
@ -262,13 +263,14 @@ func (tx *Tx) CurTime() (time.Time, error) {
case Sqlite3: case Sqlite3:
var timestring string var timestring string
if err := tx.QueryRow("select now()").Scan(&timestring); err != nil { if err := tx.QueryRow("select now()").Scan(&timestring); 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: case Postgres:
var now time.Time var now time.Time
if err := tx.QueryRow("select now()").Scan(&now); err != nil { if err := tx.QueryRow("select now()").Scan(&now); err != nil {
return time.Time{}, err return time.Time{}, errors.WithStack(err)
} }
return now, nil return now, nil
} }

89
internal/errors/errors.go Normal file
View File

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

47
internal/errors/format.go Normal file
View File

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

38
internal/errors/go113.go Normal file
View File

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

181
internal/errors/stack.go Normal file
View File

@ -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 (<funcname>\n\t<path>)
// %+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:]
}

View File

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

View File

@ -22,6 +22,7 @@ import (
"strings" "strings"
"time" "time"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"github.com/rs/zerolog" "github.com/rs/zerolog"
@ -29,7 +30,6 @@ import (
etcdclientv3 "go.etcd.io/etcd/clientv3" etcdclientv3 "go.etcd.io/etcd/clientv3"
"go.etcd.io/etcd/clientv3/namespace" "go.etcd.io/etcd/clientv3/namespace"
"go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes"
errors "golang.org/x/xerrors"
) )
var ( var (
@ -65,7 +65,7 @@ func FromEtcdError(err error) error {
if errors.Is(err, rpctypes.ErrKeyNotFound) { if errors.Is(err, rpctypes.ErrKeyNotFound) {
return ErrKeyNotFound return ErrKeyNotFound
} }
return err return errors.WithStack(err)
} }
type Store struct { type Store struct {
@ -90,7 +90,7 @@ func New(cfg Config) (*Store, error) {
for _, e := range endpoints { for _, e := range endpoints {
u, err := url.Parse(e) u, err := url.Parse(e)
if err != nil { 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 == "" { if scheme == "" {
scheme = u.Scheme scheme = u.Scheme
@ -108,7 +108,7 @@ func New(cfg Config) (*Store, error) {
var err error var err error
tlsConfig, err = util.NewTLSConfig(cfg.CertFile, cfg.KeyFile, cfg.CAFile, cfg.SkipTLSVerify) tlsConfig, err = util.NewTLSConfig(cfg.CertFile, cfg.KeyFile, cfg.CAFile, cfg.SkipTLSVerify)
if err != nil { 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) c, err := etcdclientv3.New(config)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
c.KV = namespace.NewKV(c.KV, prefix) 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 { if options.TTL > 0 {
lease, err := s.c.Grant(ctx, int64(options.TTL.Seconds())) lease, err := s.c.Grant(ctx, int64(options.TTL.Seconds()))
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
etcdv3Options = append(etcdv3Options, etcdclientv3.WithLease(lease.ID)) 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 { if options.TTL > 0 {
lease, err := s.c.Grant(ctx, int64(options.TTL)) lease, err := s.c.Grant(ctx, int64(options.TTL))
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
etcdv3Options = append(etcdv3Options, etcdclientv3.WithLease(lease.ID)) 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 { func (s *Store) Delete(ctx context.Context, key string) error {
_, err := s.c.Delete(ctx, key) _, err := s.c.Delete(ctx, key)
return err return errors.WithStack(err)
} }
func (s *Store) DeletePrefix(ctx context.Context, prefix string) error { 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...) _, 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) { 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 { 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) { 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() ).Commit()
if err != nil { if err != nil {
return version, rev, err return version, rev, errors.WithStack(err)
} }
curRev := resp.Header.Revision 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 { if _, err = s.c.Compact(ctx, rev); err != nil {
s.log.Warn().Msgf("compact error: %v", err) 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) s.log.Info().Msgf("compacted revision: %d", rev)
return curVersion, curRev, nil return curVersion, curRev, nil

View File

@ -16,6 +16,7 @@
// have the TryLock function not yet available on stable v3.4 client // have the TryLock function not yet available on stable v3.4 client
// Remove this when updating the client to a version providing TryLock // Remove this when updating the client to a version providing TryLock
//nolint:wrapcheck
package etcd package etcd
import ( import (

View File

@ -24,10 +24,10 @@ import (
"regexp" "regexp"
"strings" "strings"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"github.com/rs/zerolog" "github.com/rs/zerolog"
errors "golang.org/x/xerrors"
) )
var ( var (
@ -109,21 +109,21 @@ func InfoRefsResponse(ctx context.Context, repoPath, serviceName string) ([]byte
git := &util.Git{} git := &util.Git{}
out, err := git.Output(ctx, nil, serviceName, "--stateless-rpc", "--advertise-refs", repoPath) out, err := git.Output(ctx, nil, serviceName, "--stateless-rpc", "--advertise-refs", repoPath)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
buf.Write(out) 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 { func gitService(ctx context.Context, w io.Writer, r io.Reader, repoPath, serviceName string) error {
git := &util.Git{GitDir: repoPath} 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 { func gitFetchFile(ctx context.Context, w io.Writer, r io.Reader, repoPath, ref, path string) error {
git := &util.Git{GitDir: repoPath} 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") var ErrWrongRepoPath = errors.New("wrong repository path")

View File

@ -20,11 +20,11 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
"github.com/rs/zerolog" "github.com/rs/zerolog"
errors "golang.org/x/xerrors"
) )
const ( const (
@ -35,24 +35,24 @@ const (
func copyFile(src, dest string) error { func copyFile(src, dest string) error {
srcf, err := os.Open(src) srcf, err := os.Open(src)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer srcf.Close() defer srcf.Close()
destf, err := os.Create(dest) destf, err := os.Create(dest)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer destf.Close() defer destf.Close()
_, err = io.Copy(destf, srcf) _, err = io.Copy(destf, srcf)
return err return errors.WithStack(err)
} }
func fileExists(path string) (bool, error) { func fileExists(path string) (bool, error) {
_, err := os.Stat(path) _, err := os.Stat(path)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return false, err return false, errors.WithStack(err)
} }
return !os.IsNotExist(err), nil return !os.IsNotExist(err), nil
} }
@ -62,24 +62,24 @@ func GitDir() (string, error) {
git := &util.Git{} git := &util.Git{}
lines, err := git.OutputLines(context.Background(), nil, "rev-parse", "--git-dir") lines, err := git.OutputLines(context.Background(), nil, "rev-parse", "--git-dir")
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
if len(lines) != 1 { if len(lines) != 1 {
return "", errors.Errorf("received %d lines, expected one line", len(lines)) 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) { func currentGitBranch() (string, error) {
git := &util.Git{} git := &util.Git{}
lines, err := git.OutputLines(context.Background(), nil, "symbolic-ref", "--short", "HEAD") lines, err := git.OutputLines(context.Background(), nil, "symbolic-ref", "--short", "HEAD")
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
if len(lines) != 1 { if len(lines) != 1 {
return "", errors.Errorf("received %d lines, expected one line", len(lines)) 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 // 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}} git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}}
lines, err := git.OutputLines(context.Background(), nil, "write-tree") lines, err := git.OutputLines(context.Background(), nil, "write-tree")
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
if len(lines) != 1 { if len(lines) != 1 {
return "", errors.Errorf("received %d lines, expected one line", len(lines)) 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) { func gitCommitTree(message, treeSHA string) (string, error) {
git := &util.Git{} git := &util.Git{}
lines, err := git.OutputLines(context.Background(), nil, "commit-tree", "-m", message, treeSHA) lines, err := git.OutputLines(context.Background(), nil, "commit-tree", "-m", message, treeSHA)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
if len(lines) != 1 { if len(lines) != 1 {
return "", errors.Errorf("received %d lines, expected one line", len(lines)) 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 { func gitUpdateRef(message, ref, commitSHA string) error {
git := &util.Git{} git := &util.Git{}
_, err := git.Output(context.Background(), nil, "update-ref", "-m", message, ref, commitSHA) _, err := git.Output(context.Background(), nil, "update-ref", "-m", message, ref, commitSHA)
return err return errors.WithStack(err)
} }
func gitUpdateFiles(indexPath string) error { func gitUpdateFiles(indexPath string) error {
git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}} git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}}
_, err := git.Output(context.Background(), nil, "add", "-u") _, err := git.Output(context.Background(), nil, "add", "-u")
return err return errors.WithStack(err)
} }
func gitAddUntrackedFiles(indexPath string) error { func gitAddUntrackedFiles(indexPath string) error {
git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}} git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}}
_, err := git.Output(context.Background(), nil, "add", ".") _, err := git.Output(context.Background(), nil, "add", ".")
return err return errors.WithStack(err)
} }
func gitAddIgnoredFiles(indexPath string) error { func gitAddIgnoredFiles(indexPath string) error {
git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}} git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + indexPath}}
_, err := git.Output(context.Background(), nil, "add", "-f", "-A", ".") _, err := git.Output(context.Background(), nil, "add", "-f", "-A", ".")
return err return errors.WithStack(err)
} }
func GitAddRemote(configPath, name, url string) error { func GitAddRemote(configPath, name, url string) error {
git := &util.Git{} git := &util.Git{}
_, err := git.Output(context.Background(), nil, "remote", "add", name, url) _, err := git.Output(context.Background(), nil, "remote", "add", name, url)
return err return errors.WithStack(err)
} }
func GitPush(configPath, remote, branch string) error { func GitPush(configPath, remote, branch string) error {
git := &util.Git{} git := &util.Git{}
_, err := git.Output(context.Background(), nil, "push", remote, branch, "-f") _, err := git.Output(context.Background(), nil, "push", remote, branch, "-f")
return err return errors.WithStack(err)
} }
type GitSaveConfig struct { type GitSaveConfig struct {
@ -178,7 +178,7 @@ func (s *GitSave) RefsPrefix() string {
func (s *GitSave) Save(message, branchName string) (string, error) { func (s *GitSave) Save(message, branchName string) (string, error) {
gitdir, err := GitDir() gitdir, err := GitDir()
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
tmpIndexPath := filepath.Join(gitdir, "gitsave-index-"+uuid.Must(uuid.NewV4()).String()) 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() curBranch, err := currentGitBranch()
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
indexExists, err := fileExists(indexPath) indexExists, err := fileExists(indexPath)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
if indexExists { if indexExists {
// copy current git index to a temporary index // copy current git index to a temporary index
if err := copyFile(indexPath, tmpIndexPath); err != nil { if err := copyFile(indexPath, tmpIndexPath); err != nil {
return "", err return "", errors.WithStack(err)
} }
s.log.Info().Msgf("created temporary index: %s", tmpIndexPath) s.log.Info().Msgf("created temporary index: %s", tmpIndexPath)
// read the current branch tree information into the index // read the current branch tree information into the index
git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + tmpIndexPath}} git := &util.Git{Env: []string{"GIT_INDEX_FILE=" + tmpIndexPath}}
_, err = git.Output(context.Background(), nil, "read-tree", curBranch) _, err = git.Output(context.Background(), nil, "read-tree", curBranch)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
} else { } else {
s.log.Info().Msgf("index %s does not exist", indexPath) 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") s.log.Info().Msgf("updating files already in the index")
if err := gitUpdateFiles(tmpIndexPath); err != nil { if err := gitUpdateFiles(tmpIndexPath); err != nil {
return "", err return "", errors.WithStack(err)
} }
if s.conf.AddUntracked { if s.conf.AddUntracked {
s.log.Info().Msgf("adding untracked files") s.log.Info().Msgf("adding untracked files")
if err := gitAddUntrackedFiles(tmpIndexPath); err != nil { if err := gitAddUntrackedFiles(tmpIndexPath); err != nil {
return "", err return "", errors.WithStack(err)
} }
} }
if s.conf.AddIgnored { if s.conf.AddIgnored {
s.log.Info().Msgf("adding ignored files") s.log.Info().Msgf("adding ignored files")
if err := gitAddIgnoredFiles(tmpIndexPath); err != nil { if err := gitAddIgnoredFiles(tmpIndexPath); err != nil {
return "", err return "", errors.WithStack(err)
} }
} }
s.log.Info().Msgf("writing tree file") s.log.Info().Msgf("writing tree file")
treeSHA, err := gitWriteTree(tmpIndexPath) treeSHA, err := gitWriteTree(tmpIndexPath)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
s.log.Info().Msgf("tree: %s", treeSHA) s.log.Info().Msgf("tree: %s", treeSHA)
s.log.Info().Msgf("committing tree") s.log.Info().Msgf("committing tree")
commitSHA, err := gitCommitTree(message, treeSHA) commitSHA, err := gitCommitTree(message, treeSHA)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
s.log.Info().Msgf("commit: %s", commitSHA) s.log.Info().Msgf("commit: %s", commitSHA)
s.log.Info().Msgf("updating ref") s.log.Info().Msgf("updating ref")
if err = gitUpdateRef("git-save", filepath.Join(s.refsPrefix, branchName), commitSHA); err != nil { if err = gitUpdateRef("git-save", filepath.Join(s.refsPrefix, branchName), commitSHA); err != nil {
return "", err return "", errors.WithStack(err)
} }
return commitSHA, nil return commitSHA, nil

View File

@ -26,6 +26,7 @@ import (
"strings" "strings"
"time" "time"
"agola.io/agola/internal/errors"
gitsource "agola.io/agola/internal/gitsources" gitsource "agola.io/agola/internal/gitsources"
"agola.io/agola/internal/services/types" "agola.io/agola/internal/services/types"
"agola.io/agola/internal/util" "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) { 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) u, err := url.Parse(c.url + "/" + path)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
u.RawQuery = query.Encode() u.RawQuery = query.Encode()
req, err := http.NewRequest(method, u.String(), ibody) req, err := http.NewRequest(method, u.String(), ibody)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
for k, v := range header { for k, v := range header {
req.Header[k] = 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(method, path string, query url.Values, header http.Header, ibody io.Reader) (*http.Response, error) { 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) resp, err := c.doRequest(method, path, query, header, ibody)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if err := util.ErrFromRemote(resp); err != nil { if err := util.ErrFromRemote(resp); err != nil {
return resp, err return resp, errors.WithStack(err)
} }
return resp, nil 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) { 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) resp, err := c.getResponse("GET", fmt.Sprintf("%s.git/raw/%s/%s", repopath, commit, file), nil, nil, nil)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
defer resp.Body.Close() defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body) 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 { 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) { func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) {

View File

@ -28,11 +28,11 @@ import (
"strings" "strings"
"time" "time"
"agola.io/agola/internal/errors"
gitsource "agola.io/agola/internal/gitsources" gitsource "agola.io/agola/internal/gitsources"
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"golang.org/x/oauth2" "golang.org/x/oauth2"
errors "golang.org/x/xerrors"
) )
const ( const (
@ -146,7 +146,7 @@ func (c *Client) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, er
var config = c.oauth2Config(callbackURL) var config = c.oauth2Config(callbackURL)
token, err := config.Exchange(ctx, code) token, err := config.Exchange(ctx, code)
if err != nil { 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 return token, nil
} }
@ -158,7 +158,9 @@ func (c *Client) RefreshOauth2Token(refreshToken string) (*oauth2.Token, error)
var config = c.oauth2Config("") var config = c.oauth2Config("")
token := &oauth2.Token{RefreshToken: refreshToken} token := &oauth2.Token{RefreshToken: refreshToken}
ts := config.TokenSource(ctx, token) 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) { 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) tokens := make([]*gitea.AccessToken, 0, 10)
req, err := http.NewRequest("GET", c.APIURL+"/api/v1"+fmt.Sprintf("/users/%s/tokens", username), nil) req, err := http.NewRequest("GET", c.APIURL+"/api/v1"+fmt.Sprintf("/users/%s/tokens", username), nil)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(username+":"+password))) req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(username+":"+password)))
resp, err := c.oauth2HTTPClient.Do(req) resp, err := c.oauth2HTTPClient.Do(req)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
if resp.StatusCode == http.StatusUnauthorized { if resp.StatusCode == http.StatusUnauthorized {
return "", gitsource.ErrUnauthorized return "", errors.WithStack(gitsource.ErrUnauthorized)
} }
if resp.StatusCode/100 != 2 { if resp.StatusCode/100 != 2 {
return "", errors.Errorf("gitea api status code %d", resp.StatusCode) 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) dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&tokens); err != nil { if err := dec.Decode(&tokens); err != nil {
return "", err return "", errors.WithStack(err)
} }
for _, token := range tokens { for _, token := range tokens {
if token.Name == tokenName { if token.Name == tokenName {
@ -206,7 +208,7 @@ func (c *Client) LoginPassword(username, password, tokenName string) (string, er
gitea.CreateAccessTokenOption{Name: tokenName}, gitea.CreateAccessTokenOption{Name: tokenName},
) )
if terr != nil { if terr != nil {
return "", terr return "", errors.WithStack(terr)
} }
accessToken = token.Token accessToken = token.Token
} }
@ -217,7 +219,7 @@ func (c *Client) LoginPassword(username, password, tokenName string) (string, er
func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) {
user, err := c.client.GetMyUserInfo() user, err := c.client.GetMyUserInfo()
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return &gitsource.UserInfo{ return &gitsource.UserInfo{
ID: strconv.FormatInt(user.ID, 10), 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) { func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
rr, err := c.client.GetRepo(owner, reponame) rr, err := c.client.GetRepo(owner, reponame)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return fromGiteaRepo(rr), nil 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) { func (c *Client) GetFile(repopath, commit, file string) ([]byte, error) {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
data, err := c.client.GetFile(owner, reponame, commit, file) 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 { func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if _, err = c.client.CreateDeployKey(owner, reponame, gitea.CreateKeyOption{ if _, err = c.client.CreateDeployKey(owner, reponame, gitea.CreateKeyOption{
Title: title, Title: title,
Key: pubKey, Key: pubKey,
ReadOnly: readonly, ReadOnly: readonly,
}); err != nil { }); err != nil {
return errors.Errorf("error creating deploy key: %w", err) return errors.Wrapf(err, "error creating deploy key")
} }
return nil 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 { func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { 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 // 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 // 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 // when the public key value has changed
keys, err := c.client.ListDeployKeys(owner, reponame, gitea.ListDeployKeysOptions{}) keys, err := c.client.ListDeployKeys(owner, reponame, gitea.ListDeployKeysOptions{})
if err != 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 { for _, key := range keys {
@ -283,7 +285,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool)
return nil return nil
} }
if err := c.client.DeleteDeployKey(owner, reponame, key.ID); err != 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, Key: pubKey,
ReadOnly: readonly, ReadOnly: readonly,
}); err != nil { }); err != nil {
return errors.Errorf("error creating deploy key: %w", err) return errors.Wrapf(err, "error creating deploy key")
} }
return nil return nil
@ -302,17 +304,17 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool)
func (c *Client) DeleteDeployKey(repopath, title string) error { func (c *Client) DeleteDeployKey(repopath, title string) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
keys, err := c.client.ListDeployKeys(owner, reponame, gitea.ListDeployKeysOptions{}) keys, err := c.client.ListDeployKeys(owner, reponame, gitea.ListDeployKeysOptions{})
if err != 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 { for _, key := range keys {
if key.Title == title { if key.Title == title {
if err := c.client.DeleteDeployKey(owner, reponame, key.ID); err != 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")
} }
} }
} }
@ -323,7 +325,7 @@ func (c *Client) DeleteDeployKey(repopath, title string) error {
func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { func (c *Client) CreateRepoWebhook(repopath, url, secret string) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
opts := gitea.CreateHookOption{ 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 { 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 return nil
@ -347,11 +349,11 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error {
func (c *Client) DeleteRepoWebhook(repopath, u string) error { func (c *Client) DeleteRepoWebhook(repopath, u string) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
hooks, err := c.client.ListRepoHooks(owner, reponame, gitea.ListHooksOptions{}) hooks, err := c.client.ListRepoHooks(owner, reponame, gitea.ListHooksOptions{})
if err != 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 // 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 { for _, hook := range hooks {
if hook.Config["url"] == u { if hook.Config["url"] == u {
if err := c.client.DeleteRepoHook(owner, reponame, hook.ID); err != nil { 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 { func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource.CommitStatus, targetURL, description, context string) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
_, err = c.client.CreateStatus(owner, reponame, commitSHA, gitea.CreateStatusOption{ _, err = c.client.CreateStatus(owner, reponame, commitSHA, gitea.CreateStatusOption{
State: fromCommitStatus(status), State: fromCommitStatus(status),
@ -378,7 +380,7 @@ func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource
Description: description, Description: description,
Context: context, Context: context,
}) })
return err return errors.WithStack(err)
} }
func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) {
@ -396,7 +398,7 @@ func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) {
) )
if err != nil { if err != nil {
return []*gitsource.RepoInfo{}, err return []*gitsource.RepoInfo{}, errors.WithStack(err)
} }
for _, repo := range remoteRepos { 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) { func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
remoteRefs, err := c.client.GetRepoRefs(owner, reponame, ref) remoteRefs, err := c.client.GetRepoRefs(owner, reponame, ref)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if len(remoteRefs) == 0 { if len(remoteRefs) == 0 {
return nil, errors.Errorf("no ref %q for repository %q", ref, repopath) 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) { func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
commit, err := c.client.GetSingleCommit(owner, reponame, commitSHA) commit, err := c.client.GetSingleCommit(owner, reponame, commitSHA)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return &gitsource.Commit{ return &gitsource.Commit{

View File

@ -27,9 +27,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/services/types" "agola.io/agola/internal/services/types"
errors "golang.org/x/xerrors"
) )
const ( const (
@ -48,7 +47,7 @@ const (
func (c *Client) ParseWebhook(r *http.Request, secret string) (*types.WebhookData, error) { func (c *Client) ParseWebhook(r *http.Request, secret string) (*types.WebhookData, error) {
data, err := ioutil.ReadAll(io.LimitReader(r.Body, 10*1024*1024)) data, err := ioutil.ReadAll(io.LimitReader(r.Body, 10*1024*1024))
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
// verify signature // verify signature
@ -83,7 +82,7 @@ func parsePushHook(data []byte) (*types.WebhookData, error) {
push := new(pushHook) push := new(pushHook)
err := json.Unmarshal(data, push) err := json.Unmarshal(data, push)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return webhookDataFromPush(push) return webhookDataFromPush(push)
@ -93,7 +92,7 @@ func parsePullRequestHook(data []byte) (*types.WebhookData, error) {
prhook := new(pullRequestHook) prhook := new(pullRequestHook)
err := json.Unmarshal(data, prhook) err := json.Unmarshal(data, prhook)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
// skip non open pull requests // skip non open pull requests
@ -144,7 +143,7 @@ func webhookDataFromPush(hook *pushHook) (*types.WebhookData, error) {
whd.Message = fmt.Sprintf("Tag %s", whd.Tag) whd.Message = fmt.Sprintf("Tag %s", whd.Tag)
default: default:
// ignore received webhook since it doesn't have a ref we're interested in // 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 return whd, nil

View File

@ -28,11 +28,11 @@ import (
"strings" "strings"
"time" "time"
"agola.io/agola/internal/errors"
gitsource "agola.io/agola/internal/gitsources" gitsource "agola.io/agola/internal/gitsources"
"github.com/google/go-github/v29/github" "github.com/google/go-github/v29/github"
"golang.org/x/oauth2" "golang.org/x/oauth2"
errors "golang.org/x/xerrors"
) )
var ( var (
@ -81,7 +81,7 @@ func fromCommitStatus(status gitsource.CommitStatus) string {
case gitsource.CommitStatusFailed: case gitsource.CommitStatusFailed:
return "failure" return "failure"
default: 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 != "" { if t.token != "" {
r.Header.Set("Authorization", "Bearer "+t.token) r.Header.Set("Authorization", "Bearer "+t.token)
} }
//nolint:wrapcheck
return t.rt.RoundTrip(r) return t.rt.RoundTrip(r)
} }
@ -184,7 +186,7 @@ func (c *Client) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, er
var config = c.oauth2Config(callbackURL) var config = c.oauth2Config(callbackURL)
token, err := config.Exchange(ctx, code) token, err := config.Exchange(ctx, code)
if err != nil { 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 return token, nil
} }
@ -196,13 +198,15 @@ func (c *Client) RefreshOauth2Token(refreshToken string) (*oauth2.Token, error)
var config = c.oauth2Config("") var config = c.oauth2Config("")
token := &oauth2.Token{RefreshToken: refreshToken} token := &oauth2.Token{RefreshToken: refreshToken}
ts := config.TokenSource(ctx, token) ts := config.TokenSource(ctx, token)
return ts.Token() ntoken, err := ts.Token()
return ntoken, errors.WithStack(err)
} }
func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) {
user, _, err := c.client.Users.Get(context.TODO(), "") user, _, err := c.client.Users.Get(context.TODO(), "")
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
userInfo := &gitsource.UserInfo{ userInfo := &gitsource.UserInfo{
@ -219,11 +223,11 @@ func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) {
func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) { func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
rr, _, err := c.client.Repositories.Get(context.TODO(), owner, reponame) rr, _, err := c.client.Repositories.Get(context.TODO(), owner, reponame)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return fromGithubRepo(rr), nil 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) { func (c *Client) GetFile(repopath, commit, file string) ([]byte, error) {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { 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}) r, err := c.client.Repositories.DownloadContents(context.TODO(), owner, reponame, file, &github.RepositoryContentGetOptions{Ref: commit})
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
defer r.Close() 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 { func (c *Client) CreateDeployKey(repopath, title, pubKey string, readonly bool) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if _, _, err = c.client.Repositories.CreateKey(context.TODO(), owner, reponame, &github.Key{ if _, _, err = c.client.Repositories.CreateKey(context.TODO(), owner, reponame, &github.Key{
Title: github.String(title), Title: github.String(title),
Key: github.String(pubKey), Key: github.String(pubKey),
ReadOnly: github.Bool(readonly), ReadOnly: github.Bool(readonly),
}); err != nil { }); err != nil {
return errors.Errorf("error creating deploy key: %w", err) return errors.Wrapf(err, "error creating deploy key")
} }
return nil 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 { func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { 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 // 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 // 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 // when the public key value has changed
keys, _, err := c.client.Repositories.ListKeys(context.TODO(), owner, reponame, nil) keys, _, err := c.client.Repositories.ListKeys(context.TODO(), owner, reponame, nil)
if err != 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 { for _, key := range keys {
@ -277,7 +282,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool)
return nil return nil
} }
if _, err := c.client.Repositories.DeleteKey(context.TODO(), owner, reponame, *key.ID); err != 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), Key: github.String(pubKey),
ReadOnly: github.Bool(readonly), ReadOnly: github.Bool(readonly),
}); err != nil { }); err != nil {
return errors.Errorf("error creating deploy key: %w", err) return errors.Wrapf(err, "error creating deploy key")
} }
return nil return nil
@ -296,17 +301,17 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool)
func (c *Client) DeleteDeployKey(repopath, title string) error { func (c *Client) DeleteDeployKey(repopath, title string) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
keys, _, err := c.client.Repositories.ListKeys(context.TODO(), owner, reponame, nil) keys, _, err := c.client.Repositories.ListKeys(context.TODO(), owner, reponame, nil)
if err != 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 { for _, key := range keys {
if *key.Title == title { if *key.Title == title {
if _, err := c.client.Repositories.DeleteKey(context.TODO(), owner, reponame, *key.ID); err != 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")
} }
} }
} }
@ -317,7 +322,7 @@ func (c *Client) DeleteDeployKey(repopath, title string) error {
func (c *Client) CreateRepoWebhook(repopath, url, secret string) error { func (c *Client) CreateRepoWebhook(repopath, url, secret string) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
hook := &github.Hook{ 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 { 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 return nil
@ -340,7 +345,7 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error {
func (c *Client) DeleteRepoWebhook(repopath, u string) error { func (c *Client) DeleteRepoWebhook(repopath, u string) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
hooks := []*github.Hook{} hooks := []*github.Hook{}
@ -349,7 +354,7 @@ func (c *Client) DeleteRepoWebhook(repopath, u string) error {
for { for {
pHooks, resp, err := c.client.Repositories.ListHooks(context.TODO(), owner, reponame, opt) pHooks, resp, err := c.client.Repositories.ListHooks(context.TODO(), owner, reponame, opt)
if err != nil { if err != nil {
return errors.Errorf("error retrieving repository webhooks: %w", err) return errors.Wrapf(err, "error retrieving repository webhooks")
} }
hooks = append(hooks, pHooks...) hooks = append(hooks, pHooks...)
if resp.NextPage == 0 { if resp.NextPage == 0 {
@ -363,7 +368,7 @@ func (c *Client) DeleteRepoWebhook(repopath, u string) error {
for _, hook := range hooks { for _, hook := range hooks {
if hook.Config["url"] == u { if hook.Config["url"] == u {
if _, err := c.client.Repositories.DeleteHook(context.TODO(), owner, reponame, *hook.ID); err != nil { 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 { func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource.CommitStatus, targetURL, description, statusContext string) error {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
_, _, err = c.client.Repositories.CreateStatus(context.TODO(), owner, reponame, commitSHA, &github.RepoStatus{ _, _, err = c.client.Repositories.CreateStatus(context.TODO(), owner, reponame, commitSHA, &github.RepoStatus{
State: github.String(fromCommitStatus(status)), State: github.String(fromCommitStatus(status)),
@ -382,7 +387,7 @@ func (c *Client) CreateCommitStatus(repopath, commitSHA string, status gitsource
Description: github.String(description), Description: github.String(description),
Context: github.String(statusContext), Context: github.String(statusContext),
}) })
return err return errors.WithStack(err)
} }
func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) {
@ -392,7 +397,7 @@ func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) {
for { for {
pRemoteRepos, resp, err := c.client.Repositories.List(context.TODO(), "", opt) pRemoteRepos, resp, err := c.client.Repositories.List(context.TODO(), "", opt)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
remoteRepos = append(remoteRepos, pRemoteRepos...) remoteRepos = append(remoteRepos, pRemoteRepos...)
if resp.NextPage == 0 { 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) { func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
remoteRef, _, err := c.client.Git.GetRef(context.TODO(), owner, reponame, ref) remoteRef, _, err := c.client.Git.GetRef(context.TODO(), owner, reponame, ref)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return fromGithubRef(remoteRef) return fromGithubRef(remoteRef)
@ -445,7 +450,7 @@ func fromGithubRef(remoteRef *github.Reference) (*gitsource.Ref, error) {
switch t { switch t {
case "commit": case "commit":
default: default:
return nil, fmt.Errorf("unsupported object type: %s", t) return nil, errors.Errorf("unsupported object type: %s", t)
} }
return &gitsource.Ref{ return &gitsource.Ref{
@ -467,19 +472,19 @@ func (c *Client) RefType(ref string) (gitsource.RefType, string, error) {
return gitsource.RefTypePullRequest, m[1], nil return gitsource.RefTypePullRequest, m[1], nil
default: 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) { func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) {
owner, reponame, err := parseRepoPath(repopath) owner, reponame, err := parseRepoPath(repopath)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
commit, _, err := c.client.Git.GetCommit(context.TODO(), owner, reponame, commitSHA) commit, _, err := c.client.Git.GetCommit(context.TODO(), owner, reponame, commitSHA)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return &gitsource.Commit{ return &gitsource.Commit{

View File

@ -21,10 +21,10 @@ import (
"strconv" "strconv"
"strings" "strings"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/services/types" "agola.io/agola/internal/services/types"
"github.com/google/go-github/v29/github" "github.com/google/go-github/v29/github"
errors "golang.org/x/xerrors"
) )
const ( const (
@ -37,12 +37,12 @@ const (
func (c *Client) ParseWebhook(r *http.Request, secret string) (*types.WebhookData, error) { func (c *Client) ParseWebhook(r *http.Request, secret string) (*types.WebhookData, error) {
payload, err := github.ValidatePayload(r, []byte(secret)) payload, err := github.ValidatePayload(r, []byte(secret))
if err != nil { if err != nil {
return nil, errors.Errorf("wrong webhook signature: %w", err) return nil, errors.Wrapf(err, "wrong webhook signature")
} }
webHookType := github.WebHookType(r) webHookType := github.WebHookType(r)
event, err := github.ParseWebHook(webHookType, payload) event, err := github.ParseWebHook(webHookType, payload)
if err != nil { 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) { switch event := event.(type) {
case *github.PushEvent: case *github.PushEvent:
@ -96,7 +96,7 @@ func webhookDataFromPush(hook *github.PushEvent) (*types.WebhookData, error) {
default: default:
// ignore received webhook since it doesn't have a ref we're interested in // 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 return whd, nil

View File

@ -26,11 +26,11 @@ import (
"strings" "strings"
"time" "time"
"agola.io/agola/internal/errors"
gitsource "agola.io/agola/internal/gitsources" gitsource "agola.io/agola/internal/gitsources"
gitlab "github.com/xanzy/go-gitlab" gitlab "github.com/xanzy/go-gitlab"
"golang.org/x/oauth2" "golang.org/x/oauth2"
errors "golang.org/x/xerrors"
) )
var ( var (
@ -70,7 +70,7 @@ func fromCommitStatus(status gitsource.CommitStatus) gitlab.BuildStateValue {
case gitsource.CommitStatusFailed: case gitsource.CommitStatusFailed:
return gitlab.Failed return gitlab.Failed
default: 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) client := gitlab.NewOAuthClient(httpClient, opts.Token)
if err := client.SetBaseURL(opts.APIURL); err != nil { 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{ return &Client{
@ -130,7 +130,7 @@ func (c *Client) RequestOauth2Token(callbackURL, code string) (*oauth2.Token, er
var config = c.oauth2Config(callbackURL) var config = c.oauth2Config(callbackURL)
token, err := config.Exchange(ctx, code) token, err := config.Exchange(ctx, code)
if err != nil { 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 return token, nil
} }
@ -142,13 +142,15 @@ func (c *Client) RefreshOauth2Token(refreshToken string) (*oauth2.Token, error)
var config = c.oauth2Config("") var config = c.oauth2Config("")
token := &oauth2.Token{RefreshToken: refreshToken} token := &oauth2.Token{RefreshToken: refreshToken}
ts := config.TokenSource(ctx, token) 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) { func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) {
rr, _, err := c.client.Projects.GetProject(repopath, nil) rr, _, err := c.client.Projects.GetProject(repopath, nil)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return fromGitlabRepo(rr), nil return fromGitlabRepo(rr), nil
} }
@ -156,7 +158,7 @@ func (c *Client) GetRepoInfo(repopath string) (*gitsource.RepoInfo, error) {
func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) { func (c *Client) GetUserInfo() (*gitsource.UserInfo, error) {
user, _, err := c.client.Users.CurrentUser() user, _, err := c.client.Users.CurrentUser()
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return &gitsource.UserInfo{ return &gitsource.UserInfo{
ID: strconv.Itoa(user.ID), 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) { func (c *Client) GetFile(repopath, commit, file string) ([]byte, error) {
f, _, err := c.client.RepositoryFiles.GetFile(repopath, file, &gitlab.GetFileOptions{Ref: gitlab.String(commit)}) f, _, err := c.client.RepositoryFiles.GetFile(repopath, file, &gitlab.GetFileOptions{Ref: gitlab.String(commit)})
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
data, err := base64.StdEncoding.DecodeString(f.Content) data, err := base64.StdEncoding.DecodeString(f.Content)
if err != nil { 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 { 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), Title: gitlab.String(title),
Key: gitlab.String(pubKey), Key: gitlab.String(pubKey),
}); err != nil { }); err != nil {
return errors.Errorf("error creating deploy key: %w", err) return errors.Wrapf(err, "error creating deploy key")
} }
return nil 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 { func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool) error {
keys, _, err := c.client.DeployKeys.ListProjectDeployKeys(repopath, nil) keys, _, err := c.client.DeployKeys.ListProjectDeployKeys(repopath, nil)
if err != 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 { for _, key := range keys {
@ -200,7 +202,7 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool)
return nil return nil
} }
if _, err := c.client.DeployKeys.DeleteDeployKey(repopath, key.ID); err != 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, Title: &title,
Key: &pubKey, Key: &pubKey,
}); err != nil { }); err != nil {
return errors.Errorf("error creating deploy key: %w", err) return errors.Wrapf(err, "error creating deploy key")
} }
return nil return nil
@ -218,13 +220,13 @@ func (c *Client) UpdateDeployKey(repopath, title, pubKey string, readonly bool)
func (c *Client) DeleteDeployKey(repopath, title string) error { func (c *Client) DeleteDeployKey(repopath, title string) error {
keys, _, err := c.client.DeployKeys.ListProjectDeployKeys(repopath, nil) keys, _, err := c.client.DeployKeys.ListProjectDeployKeys(repopath, nil)
if err != 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 { for _, key := range keys {
if key.Title == title { if key.Title == title {
if _, err := c.client.DeployKeys.DeleteDeployKey(repopath, key.ID); err != 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")
} }
} }
} }
@ -241,7 +243,7 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error {
Token: gitlab.String(secret), Token: gitlab.String(secret),
} }
if _, _, err := c.client.Projects.AddProjectHook(repopath, opts); err != nil { 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 return nil
@ -250,7 +252,7 @@ func (c *Client) CreateRepoWebhook(repopath, url, secret string) error {
func (c *Client) DeleteRepoWebhook(repopath, u string) error { func (c *Client) DeleteRepoWebhook(repopath, u string) error {
hooks, _, err := c.client.Projects.ListProjectHooks(repopath, nil) hooks, _, err := c.client.Projects.ListProjectHooks(repopath, nil)
if err != 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 // 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 { for _, hook := range hooks {
if hook.URL == u { if hook.URL == u {
if _, err := c.client.Projects.DeleteProjectHook(repopath, hook.ID); err != nil { 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), Description: gitlab.String(description),
Context: gitlab.String(context), Context: gitlab.String(context),
}) })
return err return errors.WithStack(err)
} }
func (c *Client) ListUserRepos() ([]*gitsource.RepoInfo, error) { 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)} opts := &gitlab.ListProjectsOptions{MinAccessLevel: gitlab.AccessLevel(gitlab.MaintainerPermissions)}
remoteRepos, _, err := c.client.Projects.ListProjects(opts) remoteRepos, _, err := c.client.Projects.ListProjects(opts)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
repos := []*gitsource.RepoInfo{} repos := []*gitsource.RepoInfo{}
@ -311,7 +313,7 @@ func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) {
branch := strings.TrimPrefix(ref, "refs/heads/") branch := strings.TrimPrefix(ref, "refs/heads/")
remoteBranch, _, err := c.client.Branches.GetBranch(repopath, branch) remoteBranch, _, err := c.client.Branches.GetBranch(repopath, branch)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return &gitsource.Ref{ return &gitsource.Ref{
@ -323,7 +325,7 @@ func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) {
tag := strings.TrimPrefix(ref, "refs/heads/") tag := strings.TrimPrefix(ref, "refs/heads/")
remoteTag, _, err := c.client.Tags.GetTag(repopath, tag) remoteTag, _, err := c.client.Tags.GetTag(repopath, tag)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return &gitsource.Ref{ return &gitsource.Ref{
@ -331,7 +333,7 @@ func (c *Client) GetRef(repopath, ref string) (*gitsource.Ref, error) {
CommitSHA: remoteTag.Commit.ID, CommitSHA: remoteTag.Commit.ID,
}, nil }, nil
default: 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 return gitsource.RefTypePullRequest, m[1], nil
default: 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) { func (c *Client) GetCommit(repopath, commitSHA string) (*gitsource.Commit, error) {
commit, _, err := c.client.Commits.GetCommit(repopath, commitSHA, nil) commit, _, err := c.client.Commits.GetCommit(repopath, commitSHA, nil)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return &gitsource.Commit{ return &gitsource.Commit{

View File

@ -23,9 +23,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/services/types" "agola.io/agola/internal/services/types"
errors "golang.org/x/xerrors"
) )
const ( const (
@ -40,7 +39,7 @@ const (
func (c *Client) ParseWebhook(r *http.Request, secret string) (*types.WebhookData, error) { func (c *Client) ParseWebhook(r *http.Request, secret string) (*types.WebhookData, error) {
data, err := ioutil.ReadAll(io.LimitReader(r.Body, 10*1024*1024)) data, err := ioutil.ReadAll(io.LimitReader(r.Body, 10*1024*1024))
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
// verify token (gitlab doesn't sign the payload but just returns the provided // 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) push := new(pushHook)
err := json.Unmarshal(data, push) err := json.Unmarshal(data, push)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
// skip push events with 0 commits. i.e. a tag deletion. // 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) prhook := new(pullRequestHook)
err := json.Unmarshal(data, prhook) err := json.Unmarshal(data, prhook)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
// TODO(sgotti) skip non open pull requests // 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) whd.Message = fmt.Sprintf("Tag %s", whd.Tag)
default: default:
// ignore received webhook since it doesn't have a ref we're interested in // 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 return whd, nil

View File

@ -15,10 +15,11 @@
package gitsource package gitsource
import ( import (
"errors"
"net/http" "net/http"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/services/types" "agola.io/agola/internal/services/types"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )

View File

@ -20,6 +20,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"agola.io/agola/internal/errors"
) )
// writeFileAtomicFunc atomically writes a file, it achieves this by creating a // 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 { func writeFileAtomicFunc(p, baseDir, tmpDir string, perm os.FileMode, persist bool, writeFunc func(f io.Writer) error) error {
f, err := ioutil.TempFile(tmpDir, "tmpfile") f, err := ioutil.TempFile(tmpDir, "tmpfile")
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
err = writeFunc(f) err = writeFunc(f)
if persist && err == nil { if persist && err == nil {
@ -47,7 +49,7 @@ func writeFileAtomicFunc(p, baseDir, tmpDir string, perm os.FileMode, persist bo
} }
if err != nil { if err != nil {
os.Remove(f.Name()) os.Remove(f.Name())
return err return errors.WithStack(err)
} }
if !persist { if !persist {
@ -80,7 +82,7 @@ func writeFileAtomic(filename, baseDir, tmpDir string, perm os.FileMode, persist
return writeFileAtomicFunc(filename, baseDir, tmpDir, perm, persist, return writeFileAtomicFunc(filename, baseDir, tmpDir, perm, persist,
func(f io.Writer) error { func(f io.Writer) error {
_, err := f.Write(data) _, err := f.Write(data)
return err return errors.WithStack(err)
}) })
} }
*/ */

View File

@ -18,7 +18,7 @@ import (
"io" "io"
"time" "time"
errors "golang.org/x/xerrors" "agola.io/agola/internal/errors"
) )
type Storage interface { type Storage interface {
@ -36,10 +36,12 @@ type Storage interface {
type ErrNotExist struct { type ErrNotExist struct {
err error err error
*errors.Stack
} }
func NewErrNotExist(err error) error { func NewErrNotExist(err error) error {
return &ErrNotExist{err: err} return &ErrNotExist{err: err, Stack: errors.Callers(0)}
} }
func (e *ErrNotExist) Error() string { func (e *ErrNotExist) Error() string {

View File

@ -21,7 +21,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
errors "golang.org/x/xerrors" "agola.io/agola/internal/errors"
) )
const ( const (
@ -36,15 +36,15 @@ type PosixStorage struct {
func NewPosix(baseDir string) (*PosixStorage, error) { func NewPosix(baseDir string) (*PosixStorage, error) {
if err := os.MkdirAll(baseDir, 0770); err != nil { if err := os.MkdirAll(baseDir, 0770); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
dataDir := filepath.Join(baseDir, dataDirName) dataDir := filepath.Join(baseDir, dataDirName)
tmpDir := filepath.Join(baseDir, tmpDirName) tmpDir := filepath.Join(baseDir, tmpDirName)
if err := os.MkdirAll(dataDir, 0770); err != nil { 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 { 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{ return &PosixStorage{
dataDir: dataDir, dataDir: dataDir,
@ -59,7 +59,7 @@ func (s *PosixStorage) fsPath(p string) (string, error) {
func (s *PosixStorage) Stat(p string) (*ObjectInfo, error) { func (s *PosixStorage) Stat(p string) (*ObjectInfo, error) {
fspath, err := s.fsPath(p) fspath, err := s.fsPath(p)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
fi, err := os.Stat(fspath) fi, err := os.Stat(fspath)
@ -67,7 +67,7 @@ func (s *PosixStorage) Stat(p string) (*ObjectInfo, error) {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) 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 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) { func (s *PosixStorage) ReadObject(p string) (ReadSeekCloser, error) {
fspath, err := s.fsPath(p) fspath, err := s.fsPath(p)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
f, err := os.Open(fspath) f, err := os.Open(fspath)
if err != nil && os.IsNotExist(err) { if err != nil && os.IsNotExist(err) {
return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) 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 { func (s *PosixStorage) WriteObject(p string, data io.Reader, size int64, persist bool) error {
fspath, err := s.fsPath(p) fspath, err := s.fsPath(p)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if err := os.MkdirAll(path.Dir(fspath), 0770); err != nil { if err := os.MkdirAll(path.Dir(fspath), 0770); err != nil {
return err return errors.WithStack(err)
} }
r := data 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 { return writeFileAtomicFunc(fspath, s.dataDir, s.tmpDir, 0660, persist, func(f io.Writer) error {
_, err := io.Copy(f, r) _, err := io.Copy(f, r)
return err return errors.WithStack(err)
}) })
} }
func (s *PosixStorage) DeleteObject(p string) error { func (s *PosixStorage) DeleteObject(p string) error {
fspath, err := s.fsPath(p) fspath, err := s.fsPath(p)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if err := os.Remove(fspath); err != nil { if err := os.Remove(fspath); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) return NewErrNotExist(errors.Errorf("object %q doesn't exist", p))
} }
return err return errors.WithStack(err)
} }
// try to remove parent empty dirs // try to remove parent empty dirs
@ -179,7 +179,7 @@ func (s *PosixStorage) List(prefix, startWith, delimiter string, doneCh <-chan s
defer close(objectCh) defer close(objectCh)
err := filepath.Walk(root, func(ep string, info os.FileInfo, err error) error { err := filepath.Walk(root, func(ep string, info os.FileInfo, err error) error {
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return err return errors.WithStack(err)
} }
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil return nil
@ -191,7 +191,7 @@ func (s *PosixStorage) List(prefix, startWith, delimiter string, doneCh <-chan s
p, err = filepath.Rel(s.dataDir, p) p, err = filepath.Rel(s.dataDir, p)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if !recursive && len(p) > len(prefix) { if !recursive && len(p) > len(prefix) {
rel := strings.TrimPrefix(p, prefix) rel := strings.TrimPrefix(p, prefix)

View File

@ -23,7 +23,7 @@ import (
"strings" "strings"
"unicode/utf8" "unicode/utf8"
errors "golang.org/x/xerrors" "agola.io/agola/internal/errors"
) )
const ( const (
@ -207,15 +207,15 @@ type PosixFlatStorage struct {
func NewPosixFlat(baseDir string) (*PosixFlatStorage, error) { func NewPosixFlat(baseDir string) (*PosixFlatStorage, error) {
if err := os.MkdirAll(baseDir, 0770); err != nil { if err := os.MkdirAll(baseDir, 0770); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
dataDir := filepath.Join(baseDir, dataDirName) dataDir := filepath.Join(baseDir, dataDirName)
tmpDir := filepath.Join(baseDir, tmpDirName) tmpDir := filepath.Join(baseDir, tmpDirName)
if err := os.MkdirAll(dataDir, 0770); err != nil { 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 { 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{ return &PosixFlatStorage{
dataDir: dataDir, dataDir: dataDir,
@ -233,7 +233,7 @@ func (s *PosixFlatStorage) fsPath(p string) (string, error) {
func (s *PosixFlatStorage) Stat(p string) (*ObjectInfo, error) { func (s *PosixFlatStorage) Stat(p string) (*ObjectInfo, error) {
fspath, err := s.fsPath(p) fspath, err := s.fsPath(p)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
fi, err := os.Stat(fspath) fi, err := os.Stat(fspath)
@ -241,7 +241,7 @@ func (s *PosixFlatStorage) Stat(p string) (*ObjectInfo, error) {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) 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 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) { func (s *PosixFlatStorage) ReadObject(p string) (ReadSeekCloser, error) {
fspath, err := s.fsPath(p) fspath, err := s.fsPath(p)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
f, err := os.Open(fspath) f, err := os.Open(fspath)
if err != nil && os.IsNotExist(err) { if err != nil && os.IsNotExist(err) {
return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) 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 { func (s *PosixFlatStorage) WriteObject(p string, data io.Reader, size int64, persist bool) error {
fspath, err := s.fsPath(p) fspath, err := s.fsPath(p)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if err := os.MkdirAll(path.Dir(fspath), 0770); err != nil { if err := os.MkdirAll(path.Dir(fspath), 0770); err != nil {
return err return errors.WithStack(err)
} }
r := data 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 { return writeFileAtomicFunc(fspath, s.dataDir, s.tmpDir, 0660, persist, func(f io.Writer) error {
_, err := io.Copy(f, r) _, err := io.Copy(f, r)
return err return errors.WithStack(err)
}) })
} }
func (s *PosixFlatStorage) DeleteObject(p string) error { func (s *PosixFlatStorage) DeleteObject(p string) error {
fspath, err := s.fsPath(p) fspath, err := s.fsPath(p)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if err := os.Remove(fspath); err != nil { if err := os.Remove(fspath); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) return NewErrNotExist(errors.Errorf("object %q doesn't exist", p))
} }
return err return errors.WithStack(err)
} }
// try to remove parent empty dirs // try to remove parent empty dirs
@ -354,7 +354,7 @@ func (s *PosixFlatStorage) List(prefix, startWith, delimiter string, doneCh <-ch
defer close(objectCh) defer close(objectCh)
err := filepath.Walk(root, func(ep string, info os.FileInfo, err error) error { err := filepath.Walk(root, func(ep string, info os.FileInfo, err error) error {
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return err return errors.WithStack(err)
} }
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil return nil
@ -366,11 +366,11 @@ func (s *PosixFlatStorage) List(prefix, startWith, delimiter string, doneCh <-ch
p, err = filepath.Rel(s.dataDir, p) p, err = filepath.Rel(s.dataDir, p)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
p, _, err = unescape(p) p, _, err = unescape(p)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if !recursive && len(p) > len(prefix) { if !recursive && len(p) > len(prefix) {
rel := strings.TrimPrefix(p, prefix) rel := strings.TrimPrefix(p, prefix)
@ -390,7 +390,7 @@ func (s *PosixFlatStorage) List(prefix, startWith, delimiter string, doneCh <-ch
hasFile := true hasFile := true
_, err = os.Stat(ep + ".f") _, err = os.Stat(ep + ".f")
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return err return errors.WithStack(err)
} }
if os.IsNotExist(err) { if os.IsNotExist(err) {
hasFile = false hasFile = false

View File

@ -21,7 +21,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
errors "golang.org/x/xerrors" "agola.io/agola/internal/errors"
) )
func TestEscapeUnescape(t *testing.T) { func TestEscapeUnescape(t *testing.T) {

View File

@ -21,8 +21,8 @@ import (
"os" "os"
"strings" "strings"
"agola.io/agola/internal/errors"
minio "github.com/minio/minio-go/v6" minio "github.com/minio/minio-go/v6"
errors "golang.org/x/xerrors"
) )
type S3Storage struct { type S3Storage struct {
@ -35,21 +35,21 @@ type S3Storage struct {
func NewS3(bucket, location, endpoint, accessKeyID, secretAccessKey string, secure bool) (*S3Storage, error) { func NewS3(bucket, location, endpoint, accessKeyID, secretAccessKey string, secure bool) (*S3Storage, error) {
minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, secure) minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, secure)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
minioCore, err := minio.NewCore(endpoint, accessKeyID, secretAccessKey, secure) minioCore, err := minio.NewCore(endpoint, accessKeyID, secretAccessKey, secure)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
exists, err := minioClient.BucketExists(bucket) exists, err := minioClient.BucketExists(bucket)
if err != nil { 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 !exists {
if err := minioClient.MakeBucket(bucket, location); err != nil { 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 { if merr.StatusCode == http.StatusNotFound {
return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p)) 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 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 { if merr.StatusCode == http.StatusNotFound {
return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", filepath)) 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 { 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 { if size >= 0 {
lr := io.LimitReader(data, size) lr := io.LimitReader(data, size)
_, err := s.minioClient.PutObject(s.bucket, filepath, lr, size, minio.PutObjectOptions{ContentType: "application/octet-stream"}) _, 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 // 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 // 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") tmpfile, err := ioutil.TempFile(os.TempDir(), "s3")
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
defer tmpfile.Close() defer tmpfile.Close()
defer os.Remove(tmpfile.Name()) defer os.Remove(tmpfile.Name())
size, err = io.Copy(tmpfile, data) size, err = io.Copy(tmpfile, data)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if _, err := tmpfile.Seek(0, 0); err != nil { 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"}) _, 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 { 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 { func (s *S3Storage) List(prefix, startWith, delimiter string, doneCh <-chan struct{}) <-chan ObjectInfo {

View File

@ -19,12 +19,11 @@ import (
"strings" "strings"
"agola.io/agola/internal/config" "agola.io/agola/internal/config"
"agola.io/agola/internal/errors"
itypes "agola.io/agola/internal/services/types" itypes "agola.io/agola/internal/services/types"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
rstypes "agola.io/agola/services/runservice/types" rstypes "agola.io/agola/services/runservice/types"
"agola.io/agola/services/types" "agola.io/agola/services/types"
errors "golang.org/x/xerrors"
) )
const ( const (
@ -192,7 +191,7 @@ fi
return rws return rws
default: 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: case config.ValueTypeFromVariable:
return variables[val.Value] return variables[val.Value]
default: default:
panic(fmt.Errorf("wrong value type: %q", val.Value)) panic(errors.Errorf("wrong value type: %q", val.Value))
} }
} }

View File

@ -20,13 +20,13 @@ import (
"testing" "testing"
"agola.io/agola/internal/config" "agola.io/agola/internal/config"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
rstypes "agola.io/agola/services/runservice/types" rstypes "agola.io/agola/services/runservice/types"
"agola.io/agola/services/types" "agola.io/agola/services/types"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
errors "golang.org/x/xerrors"
) )
var uuid = &util.TestUUIDGenerator{} 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", 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", 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 { for _, tt := range tests {

View File

@ -23,8 +23,8 @@ import (
"strings" "strings"
"time" "time"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/etcd" "agola.io/agola/internal/etcd"
errors "golang.org/x/xerrors"
) )
type Sequence struct { type Sequence struct {
@ -55,11 +55,11 @@ func Parse(s string) (*Sequence, error) {
} }
epoch, err := strconv.ParseUint(parts[0], 32, 64) epoch, err := strconv.ParseUint(parts[0], 32, 64)
if err != nil { 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) c, err := strconv.ParseUint(parts[1], 32, 64)
if err != nil { 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{ return &Sequence{
Epoch: epoch, 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) { func CurSequence(ctx context.Context, e *etcd.Store, key string) (*Sequence, bool, error) {
resp, err := e.Get(ctx, key, 0) resp, err := e.Get(ctx, key, 0)
if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) {
return nil, false, err return nil, false, errors.WithStack(err)
} }
if errors.Is(err, etcd.ErrKeyNotFound) { if errors.Is(err, etcd.ErrKeyNotFound) {
return nil, false, nil 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) { if !errors.Is(err, etcd.ErrKeyNotFound) {
kv := resp.Kvs[0] kv := resp.Kvs[0]
if err := json.Unmarshal(kv.Value, &seq); err != nil { if err := json.Unmarshal(kv.Value, &seq); err != nil {
return nil, false, err return nil, false, errors.WithStack(err)
} }
} }
return seq, true, nil 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) { func IncSequence(ctx context.Context, e *etcd.Store, key string) (*Sequence, error) {
resp, err := e.Get(ctx, key, 0) resp, err := e.Get(ctx, key, 0)
if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) {
return nil, err return nil, errors.WithStack(err)
} }
var revision int64 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) { if !errors.Is(err, etcd.ErrKeyNotFound) {
kv := resp.Kvs[0] kv := resp.Kvs[0]
if err := json.Unmarshal(kv.Value, &seq); err != nil { if err := json.Unmarshal(kv.Value, &seq); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
revision = kv.ModRevision revision = kv.ModRevision
} }
@ -120,12 +120,12 @@ func IncSequence(ctx context.Context, e *etcd.Store, key string) (*Sequence, err
seqj, err := json.Marshal(seq) seqj, err := json.Marshal(seq)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
_, err = e.AtomicPut(ctx, key, seqj, revision, nil) _, err = e.AtomicPut(ctx, key, seqj, revision, nil)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return seq, nil return seq, nil

View File

@ -15,10 +15,11 @@
package sequence package sequence
import ( import (
"errors"
"math" "math"
"testing" "testing"
"agola.io/agola/internal/errors"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
) )

View File

@ -15,43 +15,48 @@
package common package common
import ( import (
"agola.io/agola/internal/errors"
gitsource "agola.io/agola/internal/gitsources" gitsource "agola.io/agola/internal/gitsources"
"agola.io/agola/internal/gitsources/gitea" "agola.io/agola/internal/gitsources/gitea"
"agola.io/agola/internal/gitsources/github" "agola.io/agola/internal/gitsources/github"
"agola.io/agola/internal/gitsources/gitlab" "agola.io/agola/internal/gitsources/gitlab"
cstypes "agola.io/agola/services/configstore/types" cstypes "agola.io/agola/services/configstore/types"
errors "golang.org/x/xerrors"
) )
func newGitea(rs *cstypes.RemoteSource, accessToken string) (*gitea.Client, error) { func newGitea(rs *cstypes.RemoteSource, accessToken string) (*gitea.Client, error) {
return gitea.New(gitea.Opts{ c, err := gitea.New(gitea.Opts{
APIURL: rs.APIURL, APIURL: rs.APIURL,
SkipVerify: rs.SkipVerify, SkipVerify: rs.SkipVerify,
Token: accessToken, Token: accessToken,
Oauth2ClientID: rs.Oauth2ClientID, Oauth2ClientID: rs.Oauth2ClientID,
Oauth2Secret: rs.Oauth2ClientSecret, Oauth2Secret: rs.Oauth2ClientSecret,
}) })
return c, errors.WithStack(err)
} }
func newGitlab(rs *cstypes.RemoteSource, accessToken string) (*gitlab.Client, error) { func newGitlab(rs *cstypes.RemoteSource, accessToken string) (*gitlab.Client, error) {
return gitlab.New(gitlab.Opts{ c, err := gitlab.New(gitlab.Opts{
APIURL: rs.APIURL, APIURL: rs.APIURL,
SkipVerify: rs.SkipVerify, SkipVerify: rs.SkipVerify,
Token: accessToken, Token: accessToken,
Oauth2ClientID: rs.Oauth2ClientID, Oauth2ClientID: rs.Oauth2ClientID,
Oauth2Secret: rs.Oauth2ClientSecret, Oauth2Secret: rs.Oauth2ClientSecret,
}) })
return c, errors.WithStack(err)
} }
func newGithub(rs *cstypes.RemoteSource, accessToken string) (*github.Client, error) { func newGithub(rs *cstypes.RemoteSource, accessToken string) (*github.Client, error) {
return github.New(github.Opts{ c, err := github.New(github.Opts{
APIURL: rs.APIURL, APIURL: rs.APIURL,
SkipVerify: rs.SkipVerify, SkipVerify: rs.SkipVerify,
Token: accessToken, Token: accessToken,
Oauth2ClientID: rs.Oauth2ClientID, Oauth2ClientID: rs.Oauth2ClientID,
Oauth2Secret: rs.Oauth2ClientSecret, Oauth2Secret: rs.Oauth2ClientSecret,
}) })
return c, errors.WithStack(err)
} }
func GetAccessToken(rs *cstypes.RemoteSource, userAccessToken, oauth2AccessToken string) (string, error) { 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 var err error
accessToken, err = GetAccessToken(rs, la.UserAccessToken, la.Oauth2AccessToken) accessToken, err = GetAccessToken(rs, la.UserAccessToken, la.Oauth2AccessToken)
if err != nil { 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 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) { 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 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) { 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 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) { 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 nil, errors.Errorf("remote source %s isn't a valid oauth2 source", rs.Name)
} }
return passwordSource, err return passwordSource, errors.WithStack(err)
} }

View File

@ -19,8 +19,8 @@ import (
"encoding/json" "encoding/json"
"time" "time"
"agola.io/agola/internal/errors"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v4"
errors "golang.org/x/xerrors"
) )
type TokenSigningData struct { 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()) return "", errors.Errorf("unsupported signing method %q", sd.Method.Alg())
} }
// Sign and get the complete encoded token as a string // 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) { func GenerateOauth2JWTToken(sd *TokenSigningData, remoteSourceName, requestType string, request interface{}) (string, error) {
requestj, err := json.Marshal(request) requestj, err := json.Marshal(request)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
return GenerateGenericJWTToken(sd, jwt.MapClaims{ return GenerateGenericJWTToken(sd, jwt.MapClaims{

View File

@ -15,13 +15,12 @@
package common package common
import ( import (
"fmt"
"net/url" "net/url"
"path" "path"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/services/types" "agola.io/agola/internal/services/types"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
errors "golang.org/x/xerrors"
) )
type GroupType string type GroupType string
@ -49,7 +48,7 @@ func WebHookEventToRunRefType(we types.WebhookEvent) types.RunRefType {
return types.RunRefTypePullRequest 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 { func GenRunGroup(baseGroupType GroupType, baseGroupID string, groupType GroupType, group string) string {

View File

@ -18,9 +18,9 @@ import (
"io/ioutil" "io/ioutil"
"time" "time"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
errors "golang.org/x/xerrors"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
@ -273,12 +273,12 @@ var defaultConfig = Config{
func Parse(configFile string, componentsNames []string) (*Config, error) { func Parse(configFile string, componentsNames []string) (*Config, error) {
configData, err := ioutil.ReadFile(configFile) configData, err := ioutil.ReadFile(configFile)
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
c := &defaultConfig c := &defaultConfig
if err := yaml.Unmarshal(configData, &c); err != nil { if err := yaml.Unmarshal(configData, &c); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return c, Validate(c, componentsNames) return c, Validate(c, componentsNames)
@ -333,7 +333,7 @@ func Validate(c *Config, componentsNames []string) error {
return errors.Errorf("gateway runserviceURL is empty") return errors.Errorf("gateway runserviceURL is empty")
} }
if err := validateWeb(&c.Gateway.Web); err != nil { 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") return errors.Errorf("configstore dataDir is empty")
} }
if err := validateWeb(&c.Configstore.Web); err != nil { 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") return errors.Errorf("runservice dataDir is empty")
} }
if err := validateWeb(&c.Runservice.Web); err != nil { 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 { 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")
} }
} }

View File

@ -20,7 +20,7 @@ import (
"path" "path"
"testing" "testing"
errors "golang.org/x/xerrors" "agola.io/agola/internal/errors"
) )
func TestParseConfig(t *testing.T) { func TestParseConfig(t *testing.T) {

View File

@ -17,13 +17,13 @@ package action
import ( import (
"agola.io/agola/internal/datamanager" "agola.io/agola/internal/datamanager"
"agola.io/agola/internal/db" "agola.io/agola/internal/db"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/etcd" "agola.io/agola/internal/etcd"
"agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/services/configstore/readdb"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/configstore/types" "agola.io/agola/services/configstore/types"
"github.com/rs/zerolog" "github.com/rs/zerolog"
errors "golang.org/x/xerrors"
) )
type ActionHandler struct { type ActionHandler struct {
@ -53,7 +53,7 @@ func (h *ActionHandler) ResolveConfigID(tx *db.Tx, configType types.ConfigType,
case types.ConfigTypeProjectGroup: case types.ConfigTypeProjectGroup:
group, err := h.readDB.GetProjectGroup(tx, ref) group, err := h.readDB.GetProjectGroup(tx, ref)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
if group == nil { if group == nil {
return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("group with ref %q doesn't exists", ref)) 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: case types.ConfigTypeProject:
project, err := h.readDB.GetProject(tx, ref) project, err := h.readDB.GetProject(tx, ref)
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
if project == nil { if project == nil {
return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with ref %q doesn't exists", ref)) return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with ref %q doesn't exists", ref))

View File

@ -18,17 +18,16 @@ import (
"context" "context"
"io" "io"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/etcd" "agola.io/agola/internal/etcd"
"agola.io/agola/internal/services/configstore/common" "agola.io/agola/internal/services/configstore/common"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
errors "golang.org/x/xerrors"
) )
func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error { func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error {
resp, err := h.e.Get(ctx, common.EtcdMaintenanceKey, 0) resp, err := h.e.Get(ctx, common.EtcdMaintenanceKey, 0)
if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) { if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) {
return err return errors.WithStack(err)
} }
if enable && len(resp.Kvs) > 0 { if enable && len(resp.Kvs) > 0 {
@ -41,7 +40,7 @@ func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error
if enable { if enable {
txResp, err := h.e.AtomicPut(ctx, common.EtcdMaintenanceKey, []byte{}, 0, nil) txResp, err := h.e.AtomicPut(ctx, common.EtcdMaintenanceKey, []byte{}, 0, nil)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if !txResp.Succeeded { if !txResp.Succeeded {
return errors.Errorf("failed to create maintenance mode key due to concurrent update") 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 { if !enable {
txResp, err := h.e.AtomicDelete(ctx, common.EtcdMaintenanceKey, resp.Kvs[0].ModRevision) txResp, err := h.e.AtomicDelete(ctx, common.EtcdMaintenanceKey, resp.Kvs[0].ModRevision)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if !txResp.Succeeded { if !txResp.Succeeded {
return errors.Errorf("failed to delete maintenance mode key due to concurrent update") 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 { 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 { func (h *ActionHandler) Import(ctx context.Context, r io.Reader) error {
if !h.maintenanceMode { if !h.maintenanceMode {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("not in maintenance mode")) 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))
} }

View File

@ -22,12 +22,13 @@ import (
"agola.io/agola/internal/datamanager" "agola.io/agola/internal/datamanager"
"agola.io/agola/internal/db" "agola.io/agola/internal/db"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/services/configstore/readdb"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/configstore/types" "agola.io/agola/services/configstore/types"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
errors "golang.org/x/xerrors"
) )
type OrgMemberResponse struct { type OrgMemberResponse struct {
@ -48,17 +49,17 @@ func (h *ActionHandler) GetOrgMembers(ctx context.Context, orgRef string) ([]*Or
var err error var err error
org, err := h.readDB.GetOrg(tx, orgRef) org, err := h.readDB.GetOrg(tx, orgRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if org == nil { if org == nil {
return util.NewAPIError(util.ErrNotExist, errors.Errorf("org %q doesn't exist", orgRef)) return util.NewAPIError(util.ErrNotExist, errors.Errorf("org %q doesn't exist", orgRef))
} }
orgUsers, err = h.readDB.GetOrgUsers(tx, org.ID) orgUsers, err = h.readDB.GetOrgUsers(tx, org.ID)
return err return errors.WithStack(err)
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
res := make([]*OrgMemberResponse, len(orgUsers)) res := make([]*OrgMemberResponse, len(orgUsers))
@ -89,13 +90,13 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization)
var err error var err error
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// check duplicate org name // check duplicate org name
o, err := h.readDB.GetOrgByName(tx, org.Name) o, err := h.readDB.GetOrgByName(tx, org.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if o != nil { if o != nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q already exists", o.Name)) 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 != "" { if org.CreatorUserID != "" {
user, err := h.readDB.GetUser(tx, org.CreatorUserID) user, err := h.readDB.GetUser(tx, org.CreatorUserID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("creator user %q doesn't exist", org.CreatorUserID)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
actions := []*datamanager.Action{} actions := []*datamanager.Action{}
@ -123,7 +124,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization)
org.CreatedAt = time.Now() org.CreatedAt = time.Now()
orgj, err := json.Marshal(org) orgj, err := json.Marshal(org)
if err != nil { 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{ actions = append(actions, &datamanager.Action{
ActionType: datamanager.ActionTypePut, ActionType: datamanager.ActionTypePut,
@ -142,7 +143,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization)
} }
orgmemberj, err := json.Marshal(orgmember) orgmemberj, err := json.Marshal(orgmember)
if err != nil { 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{ actions = append(actions, &datamanager.Action{
ActionType: datamanager.ActionTypePut, ActionType: datamanager.ActionTypePut,
@ -164,7 +165,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization)
} }
pgj, err := json.Marshal(pg) pgj, err := json.Marshal(pg)
if err != nil { 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{ actions = append(actions, &datamanager.Action{
ActionType: datamanager.ActionTypePut, ActionType: datamanager.ActionTypePut,
@ -174,7 +175,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization)
}) })
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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 { 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 // check org existance
org, err = h.readDB.GetOrgByName(tx, orgRef) org, err = h.readDB.GetOrgByName(tx, orgRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if org == nil { if org == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q doesn't exist", orgRef)) 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)} cgNames := []string{util.EncodeSha256Hex("orgid-" + org.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// TODO(sgotti) delete all project groups, projects etc... // 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) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }
// AddOrgMember add/updates an org member. // AddOrgMember add/updates an org member.
@ -237,7 +238,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string
// check existing org // check existing org
org, err = h.readDB.GetOrg(tx, orgRef) org, err = h.readDB.GetOrg(tx, orgRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if org == nil { if org == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q doesn't exists", orgRef)) 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 // check existing user
user, err = h.readDB.GetUser(tx, userRef) user, err = h.readDB.GetUser(tx, userRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exists", userRef)) 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 // fetch org member if it already exist
orgmember, err = h.readDB.GetOrgMemberByOrgUserID(tx, org.ID, user.ID) orgmember, err = h.readDB.GetOrgMemberByOrgUserID(tx, org.ID, user.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
cgNames := []string{util.EncodeSha256Hex(fmt.Sprintf("orgmember-%s-%s", org.ID, user.ID))} cgNames := []string{util.EncodeSha256Hex(fmt.Sprintf("orgmember-%s-%s", org.ID, user.ID))}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
// update if role changed // update if role changed
@ -287,7 +288,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string
actions := []*datamanager.Action{} actions := []*datamanager.Action{}
orgmemberj, err := json.Marshal(orgmember) orgmemberj, err := json.Marshal(orgmember)
if err != nil { 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{ actions = append(actions, &datamanager.Action{
ActionType: datamanager.ActionTypePut, ActionType: datamanager.ActionTypePut,
@ -297,7 +298,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string
}) })
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return orgmember, err return orgmember, errors.WithStack(err)
} }
// RemoveOrgMember removes an org member. // RemoveOrgMember removes an org member.
@ -313,7 +314,7 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str
// check existing org // check existing org
org, err = h.readDB.GetOrg(tx, orgRef) org, err = h.readDB.GetOrg(tx, orgRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if org == nil { if org == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q doesn't exists", orgRef)) 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 // check existing user
user, err = h.readDB.GetUser(tx, userRef) user, err = h.readDB.GetUser(tx, userRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exists", userRef)) 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 // check that org member exists
orgmember, err = h.readDB.GetOrgMemberByOrgUserID(tx, org.ID, user.ID) orgmember, err = h.readDB.GetOrgMemberByOrgUserID(tx, org.ID, user.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if orgmember == nil { if orgmember == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("orgmember for org %q, user %q doesn't exists", orgRef, userRef)) 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))} cgNames := []string{util.EncodeSha256Hex(fmt.Sprintf("orgmember-%s-%s", org.ID, user.ID))}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
actions := []*datamanager.Action{} actions := []*datamanager.Action{}
@ -356,5 +357,5 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str
}) })
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }

View File

@ -21,11 +21,12 @@ import (
"agola.io/agola/internal/datamanager" "agola.io/agola/internal/datamanager"
"agola.io/agola/internal/db" "agola.io/agola/internal/db"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/configstore/types" "agola.io/agola/services/configstore/types"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
errors "golang.org/x/xerrors"
) )
func (h *ActionHandler) ValidateProject(ctx context.Context, project *types.Project) error { 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 { err := h.readDB.Do(ctx, func(tx *db.Tx) error {
var err error var err error
project, err = h.readDB.GetProject(tx, projectRef) project, err = h.readDB.GetProject(tx, projectRef)
return err return errors.WithStack(err)
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if project == nil { 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) { func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Project) (*types.Project, error) {
if err := h.ValidateProject(ctx, project); err != nil { if err := h.ValidateProject(ctx, project); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var cgt *datamanager.ChangeGroupsUpdateToken var cgt *datamanager.ChangeGroupsUpdateToken
@ -94,7 +95,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec
var err error var err error
group, err := h.readDB.GetProjectGroup(tx, project.Parent.ID) group, err := h.readDB.GetProjectGroup(tx, project.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if group == nil { if group == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", project.Parent.ID)) 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) groupPath, err := h.readDB.GetProjectGroupPath(tx, group)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
pp := path.Join(groupPath, project.Name) 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)} cgNames := []string{util.EncodeSha256Hex("projectpath-" + pp)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// check duplicate project name // check duplicate project name
p, err := h.readDB.GetProjectByName(tx, project.Parent.ID, project.Name) p, err := h.readDB.GetProjectByName(tx, project.Parent.ID, project.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if p != nil { if p != nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with name %q, path %q already exists", p.Name, pp)) 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 // check that the linked account matches the remote source
user, err := h.readDB.GetUserByLinkedAccount(tx, project.LinkedAccountID) user, err := h.readDB.GetUserByLinkedAccount(tx, project.LinkedAccountID)
if err != nil { 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 { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for linked account %q doesn't exist", project.LinkedAccountID)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
project.ID = uuid.Must(uuid.NewV4()).String() 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) pcj, err := json.Marshal(project)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -168,7 +169,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return project, err return project, errors.WithStack(err)
} }
type UpdateProjectRequest struct { type UpdateProjectRequest struct {
@ -179,7 +180,7 @@ type UpdateProjectRequest struct {
func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectRequest) (*types.Project, error) { func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectRequest) (*types.Project, error) {
if err := h.ValidateProject(ctx, req.Project); err != nil { if err := h.ValidateProject(ctx, req.Project); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var cgt *datamanager.ChangeGroupsUpdateToken var cgt *datamanager.ChangeGroupsUpdateToken
@ -190,7 +191,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq
// check project exists // check project exists
p, err := h.readDB.GetProject(tx, req.ProjectRef) p, err := h.readDB.GetProject(tx, req.ProjectRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if p == nil { if p == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with ref %q doesn't exist", req.ProjectRef)) 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 // check parent project group exists
group, err := h.readDB.GetProjectGroup(tx, req.Project.Parent.ID) group, err := h.readDB.GetProjectGroup(tx, req.Project.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if group == nil { if group == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", req.Project.Parent.ID)) 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) groupPath, err := h.readDB.GetProjectGroupPath(tx, group)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
pp := path.Join(groupPath, req.Project.Name) pp := path.Join(groupPath, req.Project.Name)
@ -220,7 +221,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq
// check duplicate project name // check duplicate project name
ap, err := h.readDB.GetProjectByName(tx, req.Project.Parent.ID, req.Project.Name) ap, err := h.readDB.GetProjectByName(tx, req.Project.Parent.ID, req.Project.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if ap != nil { if ap != nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with name %q, path %q already exists", req.Project.Name, pp)) 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 // get old parent project group
curGroup, err := h.readDB.GetProjectGroup(tx, p.Parent.ID) curGroup, err := h.readDB.GetProjectGroup(tx, p.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if curGroup == nil { if curGroup == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", p.Parent.ID)) 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) curGroupPath, err := h.readDB.GetProjectGroupPath(tx, curGroup)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
pp := path.Join(curGroupPath, req.Project.Name) 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) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if req.Project.RemoteRepositoryConfigType == types.RemoteRepositoryConfigTypeRemoteSource { if req.Project.RemoteRepositoryConfigType == types.RemoteRepositoryConfigTypeRemoteSource {
// check that the linked account matches the remote source // check that the linked account matches the remote source
user, err := h.readDB.GetUserByLinkedAccount(tx, req.Project.LinkedAccountID) user, err := h.readDB.GetUserByLinkedAccount(tx, req.Project.LinkedAccountID)
if err != nil { 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 { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for linked account %q doesn't exist", req.Project.LinkedAccountID)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
pcj, err := json.Marshal(req.Project) pcj, err := json.Marshal(req.Project)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -293,7 +294,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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 { 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 // check project existance
project, err = h.readDB.GetProject(tx, projectRef) project, err = h.readDB.GetProject(tx, projectRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if project == nil { if project == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project %q doesn't exist", projectRef)) 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)} cgNames := []string{util.EncodeSha256Hex(project.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// TODO(sgotti) implement childs garbage collection // 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) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }

View File

@ -22,11 +22,12 @@ import (
"agola.io/agola/internal/datamanager" "agola.io/agola/internal/datamanager"
"agola.io/agola/internal/db" "agola.io/agola/internal/db"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/configstore/types" "agola.io/agola/services/configstore/types"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
errors "golang.org/x/xerrors"
) )
func (h *ActionHandler) GetProjectGroup(ctx context.Context, projectGroupRef string) (*types.ProjectGroup, error) { 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 { err := h.readDB.Do(ctx, func(tx *db.Tx) error {
var err error var err error
projectGroup, err = h.readDB.GetProjectGroup(tx, projectGroupRef) projectGroup, err = h.readDB.GetProjectGroup(tx, projectGroupRef)
return err return errors.WithStack(err)
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if projectGroup == nil { if projectGroup == nil {
@ -53,7 +54,7 @@ func (h *ActionHandler) GetProjectGroupSubgroups(ctx context.Context, projectGro
var err error var err error
projectGroup, err := h.readDB.GetProjectGroup(tx, projectGroupRef) projectGroup, err := h.readDB.GetProjectGroup(tx, projectGroupRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if projectGroup == nil { if projectGroup == nil {
@ -61,10 +62,10 @@ func (h *ActionHandler) GetProjectGroupSubgroups(ctx context.Context, projectGro
} }
projectGroups, err = h.readDB.GetProjectGroupSubgroups(tx, projectGroup.ID) projectGroups, err = h.readDB.GetProjectGroupSubgroups(tx, projectGroup.ID)
return err return errors.WithStack(err)
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return projectGroups, nil return projectGroups, nil
@ -76,7 +77,7 @@ func (h *ActionHandler) GetProjectGroupProjects(ctx context.Context, projectGrou
var err error var err error
projectGroup, err := h.readDB.GetProjectGroup(tx, projectGroupRef) projectGroup, err := h.readDB.GetProjectGroup(tx, projectGroupRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if projectGroup == nil { if projectGroup == nil {
@ -84,10 +85,10 @@ func (h *ActionHandler) GetProjectGroupProjects(ctx context.Context, projectGrou
} }
projects, err = h.readDB.GetProjectGroupProjects(tx, projectGroup.ID) projects, err = h.readDB.GetProjectGroupProjects(tx, projectGroup.ID)
return err return errors.WithStack(err)
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return projects, nil 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) { func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *types.ProjectGroup) (*types.ProjectGroup, error) {
if err := h.ValidateProjectGroup(ctx, projectGroup); err != nil { if err := h.ValidateProjectGroup(ctx, projectGroup); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if projectGroup.Parent.Type != types.ConfigTypeProjectGroup { 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 { err := h.readDB.Do(ctx, func(tx *db.Tx) error {
parentProjectGroup, err := h.readDB.GetProjectGroup(tx, projectGroup.Parent.ID) parentProjectGroup, err := h.readDB.GetProjectGroup(tx, projectGroup.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if parentProjectGroup == nil { if parentProjectGroup == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", projectGroup.Parent.ID)) 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) groupPath, err := h.readDB.GetProjectGroupPath(tx, parentProjectGroup)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
pp := path.Join(groupPath, projectGroup.Name) 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)} cgNames := []string{util.EncodeSha256Hex("projectpath-" + pp)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// check duplicate project group name // check duplicate project group name
pg, err := h.readDB.GetProjectGroupByName(tx, projectGroup.Parent.ID, projectGroup.Name) pg, err := h.readDB.GetProjectGroupByName(tx, projectGroup.Parent.ID, projectGroup.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if pg != nil { if pg != nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with name %q, path %q already exists", pg.Name, pp)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
projectGroup.ID = uuid.Must(uuid.NewV4()).String() 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) pgj, err := json.Marshal(projectGroup)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -193,7 +194,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return projectGroup, err return projectGroup, errors.WithStack(err)
} }
type UpdateProjectGroupRequest struct { type UpdateProjectGroupRequest struct {
@ -204,7 +205,7 @@ type UpdateProjectGroupRequest struct {
func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProjectGroupRequest) (*types.ProjectGroup, error) { func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProjectGroupRequest) (*types.ProjectGroup, error) {
if err := h.ValidateProjectGroup(ctx, req.ProjectGroup); err != nil { if err := h.ValidateProjectGroup(ctx, req.ProjectGroup); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var cgt *datamanager.ChangeGroupsUpdateToken var cgt *datamanager.ChangeGroupsUpdateToken
@ -215,7 +216,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje
// check project exists // check project exists
pg, err := h.readDB.GetProjectGroup(tx, req.ProjectGroupRef) pg, err := h.readDB.GetProjectGroup(tx, req.ProjectGroupRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if pg == nil { if pg == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with ref %q doesn't exist", req.ProjectGroupRef)) 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 // check parent exists
group, err := h.readDB.GetProjectGroup(tx, req.ProjectGroup.Parent.ID) group, err := h.readDB.GetProjectGroup(tx, req.ProjectGroup.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if group == nil { if group == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", req.ProjectGroup.Parent.ID)) 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) curPGParentPath, err := h.readDB.GetPath(tx, pg.Parent.Type, pg.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
curPGP := path.Join(curPGParentPath, pg.Name) curPGP := path.Join(curPGParentPath, pg.Name)
pgParentPath, err := h.readDB.GetPath(tx, req.ProjectGroup.Parent.Type, req.ProjectGroup.Parent.ID) pgParentPath, err := h.readDB.GetPath(tx, req.ProjectGroup.Parent.Type, req.ProjectGroup.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
pgp := path.Join(pgParentPath, req.ProjectGroup.Name) 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 // check duplicate project group name
ap, err := h.readDB.GetProjectGroupByName(tx, req.ProjectGroup.Parent.ID, req.ProjectGroup.Name) ap, err := h.readDB.GetProjectGroupByName(tx, req.ProjectGroup.Parent.ID, req.ProjectGroup.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if ap != nil { if ap != nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with name %q, path %q already exists", req.ProjectGroup.Name, pgp)) 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) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
pgj, err := json.Marshal(req.ProjectGroup) pgj, err := json.Marshal(req.ProjectGroup)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -316,7 +317,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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 { 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 // check project group existance
projectGroup, err = h.readDB.GetProjectGroup(tx, projectGroupRef) projectGroup, err = h.readDB.GetProjectGroup(tx, projectGroupRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if projectGroup == nil { if projectGroup == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group %q doesn't exist", projectGroupRef)) 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)} cgNames := []string{util.EncodeSha256Hex(projectGroup.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// TODO(sgotti) implement childs garbage collection // 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) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }

View File

@ -20,11 +20,12 @@ import (
"agola.io/agola/internal/datamanager" "agola.io/agola/internal/datamanager"
"agola.io/agola/internal/db" "agola.io/agola/internal/db"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/configstore/types" "agola.io/agola/services/configstore/types"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
errors "golang.org/x/xerrors"
) )
func (h *ActionHandler) ValidateRemoteSource(ctx context.Context, remoteSource *types.RemoteSource) error { 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) { func (h *ActionHandler) CreateRemoteSource(ctx context.Context, remoteSource *types.RemoteSource) (*types.RemoteSource, error) {
if err := h.ValidateRemoteSource(ctx, remoteSource); err != nil { if err := h.ValidateRemoteSource(ctx, remoteSource); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var cgt *datamanager.ChangeGroupsUpdateToken var cgt *datamanager.ChangeGroupsUpdateToken
@ -78,13 +79,13 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, remoteSource *ty
var err error var err error
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// check duplicate remoteSource name // check duplicate remoteSource name
u, err := h.readDB.GetRemoteSourceByName(tx, remoteSource.Name) u, err := h.readDB.GetRemoteSourceByName(tx, remoteSource.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if u != nil { if u != nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource %q already exists", u.Name)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
remoteSource.ID = uuid.Must(uuid.NewV4()).String() remoteSource.ID = uuid.Must(uuid.NewV4()).String()
rsj, err := json.Marshal(remoteSource) rsj, err := json.Marshal(remoteSource)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -111,7 +112,7 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, remoteSource *ty
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return remoteSource, err return remoteSource, errors.WithStack(err)
} }
type UpdateRemoteSourceRequest struct { type UpdateRemoteSourceRequest struct {
@ -122,7 +123,7 @@ type UpdateRemoteSourceRequest struct {
func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemoteSourceRequest) (*types.RemoteSource, error) { func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemoteSourceRequest) (*types.RemoteSource, error) {
if err := h.ValidateRemoteSource(ctx, req.RemoteSource); err != nil { if err := h.ValidateRemoteSource(ctx, req.RemoteSource); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var curRemoteSource *types.RemoteSource var curRemoteSource *types.RemoteSource
@ -135,7 +136,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot
// check remotesource exists // check remotesource exists
curRemoteSource, err = h.readDB.GetRemoteSourceByName(tx, req.RemoteSourceRef) curRemoteSource, err = h.readDB.GetRemoteSourceByName(tx, req.RemoteSourceRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if curRemoteSource == nil { if curRemoteSource == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource with ref %q doesn't exist", req.RemoteSourceRef)) 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 // check duplicate remoteSource name
u, err := h.readDB.GetRemoteSourceByName(tx, req.RemoteSource.Name) u, err := h.readDB.GetRemoteSourceByName(tx, req.RemoteSource.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if u != nil { if u != nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource %q already exists", u.Name)) 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)} cgNames := []string{util.EncodeSha256Hex("remotesourcename-" + req.RemoteSource.Name), util.EncodeSha256Hex("remotesourceid-" + req.RemoteSource.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
rsj, err := json.Marshal(req.RemoteSource) rsj, err := json.Marshal(req.RemoteSource)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -182,7 +183,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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 { 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 // check remoteSource existance
remoteSource, err = h.readDB.GetRemoteSourceByName(tx, remoteSourceName) remoteSource, err = h.readDB.GetRemoteSourceByName(tx, remoteSourceName)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if remoteSource == nil { if remoteSource == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource %q doesn't exist", remoteSourceName)) 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)} cgNames := []string{util.EncodeSha256Hex("remotesourceid-" + remoteSource.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
actions := []*datamanager.Action{ actions := []*datamanager.Action{
@ -225,5 +226,5 @@ func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, remoteSourceName
// changegroup is all the remotesources // changegroup is all the remotesources
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }

View File

@ -20,11 +20,12 @@ import (
"agola.io/agola/internal/datamanager" "agola.io/agola/internal/datamanager"
"agola.io/agola/internal/db" "agola.io/agola/internal/db"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/configstore/types" "agola.io/agola/services/configstore/types"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
errors "golang.org/x/xerrors"
) )
func (h *ActionHandler) GetSecret(ctx context.Context, secretID string) (*types.Secret, error) { 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 { err := h.readDB.Do(ctx, func(tx *db.Tx) error {
var err error var err error
secret, err = h.readDB.GetSecretByID(tx, secretID) secret, err = h.readDB.GetSecretByID(tx, secretID)
return err return errors.WithStack(err)
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if secret == nil { 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 { err := h.readDB.Do(ctx, func(tx *db.Tx) error {
parentID, err := h.ResolveConfigID(tx, parentType, parentRef) parentID, err := h.ResolveConfigID(tx, parentType, parentRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if tree { if tree {
secrets, err = h.readDB.GetSecretsTree(tx, parentType, parentID) secrets, err = h.readDB.GetSecretsTree(tx, parentType, parentID)
} else { } else {
secrets, err = h.readDB.GetSecrets(tx, parentID) secrets, err = h.readDB.GetSecrets(tx, parentID)
} }
return err return errors.WithStack(err)
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return secrets, nil 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) { func (h *ActionHandler) CreateSecret(ctx context.Context, secret *types.Secret) (*types.Secret, error) {
if err := h.ValidateSecret(ctx, secret); err != nil { if err := h.ValidateSecret(ctx, secret); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var cgt *datamanager.ChangeGroupsUpdateToken var cgt *datamanager.ChangeGroupsUpdateToken
@ -109,19 +110,19 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, secret *types.Secret)
var err error var err error
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
parentID, err := h.ResolveConfigID(tx, secret.Parent.Type, secret.Parent.ID) parentID, err := h.ResolveConfigID(tx, secret.Parent.Type, secret.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
secret.Parent.ID = parentID secret.Parent.ID = parentID
// check duplicate secret name // check duplicate secret name
s, err := h.readDB.GetSecretByName(tx, secret.Parent.ID, secret.Name) s, err := h.readDB.GetSecretByName(tx, secret.Parent.ID, secret.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if s != nil { 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)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
secret.ID = uuid.Must(uuid.NewV4()).String() secret.ID = uuid.Must(uuid.NewV4()).String()
secretj, err := json.Marshal(secret) secretj, err := json.Marshal(secret)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -149,7 +150,7 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, secret *types.Secret)
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return secret, err return secret, errors.WithStack(err)
} }
type UpdateSecretRequest struct { type UpdateSecretRequest struct {
@ -160,7 +161,7 @@ type UpdateSecretRequest struct {
func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretRequest) (*types.Secret, error) { func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretRequest) (*types.Secret, error) {
if err := h.ValidateSecret(ctx, req.Secret); err != nil { if err := h.ValidateSecret(ctx, req.Secret); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var curSecret *types.Secret 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) parentID, err := h.ResolveConfigID(tx, req.Secret.Parent.Type, req.Secret.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
req.Secret.Parent.ID = parentID req.Secret.Parent.ID = parentID
// check secret exists // check secret exists
curSecret, err = h.readDB.GetSecretByName(tx, req.Secret.Parent.ID, req.SecretName) curSecret, err = h.readDB.GetSecretByName(tx, req.Secret.Parent.ID, req.SecretName)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if curSecret == nil { 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)) 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 // check duplicate secret name
u, err := h.readDB.GetSecretByName(tx, req.Secret.Parent.ID, req.Secret.Name) u, err := h.readDB.GetSecretByName(tx, req.Secret.Parent.ID, req.Secret.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if u != nil { 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)) 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) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
secretj, err := json.Marshal(req.Secret) secretj, err := json.Marshal(req.Secret)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -229,7 +230,7 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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 { 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 var err error
parentID, err := h.ResolveConfigID(tx, parentType, parentRef) parentID, err := h.ResolveConfigID(tx, parentType, parentRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// check secret existance // check secret existance
secret, err = h.readDB.GetSecretByName(tx, parentID, secretName) secret, err = h.readDB.GetSecretByName(tx, parentID, secretName)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if secret == nil { if secret == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret with name %q doesn't exist", secretName)) 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)} cgNames := []string{util.EncodeSha256Hex("secretid-" + secret.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
actions := []*datamanager.Action{ actions := []*datamanager.Action{
@ -276,5 +277,5 @@ func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.Confi
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }

View File

@ -21,12 +21,13 @@ import (
"agola.io/agola/internal/datamanager" "agola.io/agola/internal/datamanager"
"agola.io/agola/internal/db" "agola.io/agola/internal/db"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/services/configstore/readdb" "agola.io/agola/internal/services/configstore/readdb"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/configstore/types" "agola.io/agola/services/configstore/types"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
errors "golang.org/x/xerrors"
) )
type CreateUserRequest struct { type CreateUserRequest struct {
@ -54,13 +55,13 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest)
var err error var err error
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// check duplicate user name // check duplicate user name
u, err := h.readDB.GetUserByName(tx, req.UserName) u, err := h.readDB.GetUserByName(tx, req.UserName)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if u != nil { if u != nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user with name %q already exists", u.Name)) 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 { if req.CreateUserLARequest != nil {
rs, err = h.readDB.GetRemoteSourceByName(tx, req.CreateUserLARequest.RemoteSourceName) rs, err = h.readDB.GetRemoteSourceByName(tx, req.CreateUserLARequest.RemoteSourceName)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if rs == nil { if rs == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source %q doesn't exist", req.CreateUserLARequest.RemoteSourceName)) 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) user, err := h.readDB.GetUserByLinkedAccountRemoteUserIDandSource(tx, req.CreateUserLARequest.RemoteUserID, rs.ID)
if err != nil { 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 { 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)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
user := &types.User{ user := &types.User{
@ -114,7 +115,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest)
userj, err := json.Marshal(user) userj, err := json.Marshal(user)
if err != nil { 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 // create root user project group
@ -129,7 +130,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest)
} }
pgj, err := json.Marshal(pg) pgj, err := json.Marshal(pg)
if err != nil { 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{ actions := []*datamanager.Action{
@ -148,7 +149,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest)
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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 { 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 // check user existance
user, err = h.readDB.GetUser(tx, userRef) user, err = h.readDB.GetUser(tx, userRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) 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)} cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
actions := []*datamanager.Action{ actions := []*datamanager.Action{
@ -190,7 +191,7 @@ func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error {
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }
type UpdateUserRequest struct { type UpdateUserRequest struct {
@ -210,7 +211,7 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest)
var err error var err error
user, err = h.readDB.GetUser(tx, req.UserRef) user, err = h.readDB.GetUser(tx, req.UserRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", req.UserRef)) 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) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if req.UserName != "" { if req.UserName != "" {
// check duplicate user name // check duplicate user name
u, err := h.readDB.GetUserByName(tx, req.UserName) u, err := h.readDB.GetUserByName(tx, req.UserName)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if u != nil { if u != nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user with name %q already exists", u.Name)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if req.UserName != "" { if req.UserName != "" {
@ -247,7 +248,7 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest)
userj, err := json.Marshal(user) userj, err := json.Marshal(user)
if err != nil { 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{ actions := []*datamanager.Action{
@ -260,7 +261,7 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest)
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return user, err return user, errors.WithStack(err)
} }
type CreateUserLARequest struct { type CreateUserLARequest struct {
@ -293,7 +294,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque
var err error var err error
user, err = h.readDB.GetUser(tx, req.UserRef) user, err = h.readDB.GetUser(tx, req.UserRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", req.UserRef)) 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)} cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
rs, err = h.readDB.GetRemoteSourceByName(tx, req.RemoteSourceName) rs, err = h.readDB.GetRemoteSourceByName(tx, req.RemoteSourceName)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if rs == nil { if rs == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source %q doesn't exist", req.RemoteSourceName)) 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) user, err := h.readDB.GetUserByLinkedAccountRemoteUserIDandSource(tx, req.RemoteUserID, rs.ID)
if err != nil { 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 { 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)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
if user.LinkedAccounts == nil { if user.LinkedAccounts == nil {
@ -346,7 +347,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque
userj, err := json.Marshal(user) userj, err := json.Marshal(user)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -358,7 +359,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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 { 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 var err error
user, err = h.readDB.GetUser(tx, userRef) user, err = h.readDB.GetUser(tx, userRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) 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)} cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
_, ok := user.LinkedAccounts[laID] _, ok := user.LinkedAccounts[laID]
@ -406,7 +407,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string)
userj, err := json.Marshal(user) userj, err := json.Marshal(user)
if err != nil { if err != nil {
return errors.Errorf("failed to marshal user: %w", err) return errors.Wrapf(err, "failed to marshal user")
} }
actions := []*datamanager.Action{ actions := []*datamanager.Action{
{ {
@ -418,7 +419,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string)
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }
type UpdateUserLARequest struct { type UpdateUserLARequest struct {
@ -448,7 +449,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque
var err error var err error
user, err = h.readDB.GetUser(tx, req.UserRef) user, err = h.readDB.GetUser(tx, req.UserRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", req.UserRef)) 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)} cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
la, ok := user.LinkedAccounts[req.LinkedAccountID] 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) rs, err = h.readDB.GetRemoteSource(tx, la.RemoteSourceID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if rs == nil { if rs == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source with id %q doesn't exist", la.RemoteSourceID)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
la := user.LinkedAccounts[req.LinkedAccountID] la := user.LinkedAccounts[req.LinkedAccountID]
@ -490,7 +491,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque
userj, err := json.Marshal(user) userj, err := json.Marshal(user)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -502,7 +503,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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) { 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 var err error
user, err = h.readDB.GetUser(tx, userRef) user, err = h.readDB.GetUser(tx, userRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) 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)} cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return "", err return "", errors.WithStack(err)
} }
if user.Tokens != nil { if user.Tokens != nil {
if _, ok := user.Tokens[tokenName]; ok { if _, ok := user.Tokens[tokenName]; ok {
@ -555,7 +556,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName
userj, err := json.Marshal(user) userj, err := json.Marshal(user)
if err != nil { if err != nil {
return "", errors.Errorf("failed to marshal user: %w", err) return "", errors.Wrapf(err, "failed to marshal user")
} }
actions := []*datamanager.Action{ actions := []*datamanager.Action{
{ {
@ -567,7 +568,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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 { 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 var err error
user, err = h.readDB.GetUser(tx, userRef) user, err = h.readDB.GetUser(tx, userRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) 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)} cgNames := []string{util.EncodeSha256Hex("userid-" + user.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
_, ok := user.Tokens[tokenName] _, ok := user.Tokens[tokenName]
@ -615,7 +616,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName
userj, err := json.Marshal(user) userj, err := json.Marshal(user)
if err != nil { if err != nil {
return errors.Errorf("failed to marshal user: %w", err) return errors.Wrapf(err, "failed to marshal user")
} }
actions := []*datamanager.Action{ actions := []*datamanager.Action{
{ {
@ -627,7 +628,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }
type UserOrgsResponse struct { type UserOrgsResponse struct {
@ -648,17 +649,17 @@ func (h *ActionHandler) GetUserOrgs(ctx context.Context, userRef string) ([]*Use
var err error var err error
user, err := h.readDB.GetUser(tx, userRef) user, err := h.readDB.GetUser(tx, userRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if user == nil { if user == nil {
return util.NewAPIError(util.ErrNotExist, errors.Errorf("user %q doesn't exist", userRef)) return util.NewAPIError(util.ErrNotExist, errors.Errorf("user %q doesn't exist", userRef))
} }
userOrgs, err = h.readDB.GetUserOrgs(tx, user.ID) userOrgs, err = h.readDB.GetUserOrgs(tx, user.ID)
return err return errors.WithStack(err)
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
res := make([]*UserOrgsResponse, len(userOrgs)) res := make([]*UserOrgsResponse, len(userOrgs))

View File

@ -20,11 +20,12 @@ import (
"agola.io/agola/internal/datamanager" "agola.io/agola/internal/datamanager"
"agola.io/agola/internal/db" "agola.io/agola/internal/db"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/configstore/types" "agola.io/agola/services/configstore/types"
"github.com/gofrs/uuid" "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) { 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 { err := h.readDB.Do(ctx, func(tx *db.Tx) error {
parentID, err := h.ResolveConfigID(tx, parentType, parentRef) parentID, err := h.ResolveConfigID(tx, parentType, parentRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if tree { if tree {
variables, err = h.readDB.GetVariablesTree(tx, parentType, parentID) variables, err = h.readDB.GetVariablesTree(tx, parentType, parentID)
} else { } else {
variables, err = h.readDB.GetVariables(tx, parentID) variables, err = h.readDB.GetVariables(tx, parentID)
} }
return err return errors.WithStack(err)
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
return variables, nil 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) { func (h *ActionHandler) CreateVariable(ctx context.Context, variable *types.Variable) (*types.Variable, error) {
if err := h.ValidateVariable(ctx, variable); err != nil { if err := h.ValidateVariable(ctx, variable); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var cgt *datamanager.ChangeGroupsUpdateToken var cgt *datamanager.ChangeGroupsUpdateToken
@ -85,19 +86,19 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, variable *types.Vari
var err error var err error
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
parentID, err := h.ResolveConfigID(tx, variable.Parent.Type, variable.Parent.ID) parentID, err := h.ResolveConfigID(tx, variable.Parent.Type, variable.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
variable.Parent.ID = parentID variable.Parent.ID = parentID
// check duplicate variable name // check duplicate variable name
s, err := h.readDB.GetVariableByName(tx, variable.Parent.ID, variable.Name) s, err := h.readDB.GetVariableByName(tx, variable.Parent.ID, variable.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if s != nil { 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)) 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 return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
variable.ID = uuid.Must(uuid.NewV4()).String() variable.ID = uuid.Must(uuid.NewV4()).String()
variablej, err := json.Marshal(variable) variablej, err := json.Marshal(variable)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -125,7 +126,7 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, variable *types.Vari
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return variable, err return variable, errors.WithStack(err)
} }
type UpdateVariableRequest struct { type UpdateVariableRequest struct {
@ -136,7 +137,7 @@ type UpdateVariableRequest struct {
func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableRequest) (*types.Variable, error) { func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableRequest) (*types.Variable, error) {
if err := h.ValidateVariable(ctx, req.Variable); err != nil { if err := h.ValidateVariable(ctx, req.Variable); err != nil {
return nil, err return nil, errors.WithStack(err)
} }
var curVariable *types.Variable 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) parentID, err := h.ResolveConfigID(tx, req.Variable.Parent.Type, req.Variable.Parent.ID)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
req.Variable.Parent.ID = parentID req.Variable.Parent.ID = parentID
// check variable exists // check variable exists
curVariable, err = h.readDB.GetVariableByName(tx, req.Variable.Parent.ID, req.VariableName) curVariable, err = h.readDB.GetVariableByName(tx, req.Variable.Parent.ID, req.VariableName)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if curVariable == nil { 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)) 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 // check duplicate variable name
u, err := h.readDB.GetVariableByName(tx, req.Variable.Parent.ID, req.Variable.Name) u, err := h.readDB.GetVariableByName(tx, req.Variable.Parent.ID, req.Variable.Name)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if u != nil { 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)) 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) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return nil, err return nil, errors.WithStack(err)
} }
variablej, err := json.Marshal(req.Variable) variablej, err := json.Marshal(req.Variable)
if err != nil { 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{ actions := []*datamanager.Action{
{ {
@ -205,7 +206,7 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, 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 { 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 var err error
parentID, err := h.ResolveConfigID(tx, parentType, parentRef) parentID, err := h.ResolveConfigID(tx, parentType, parentRef)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
// check variable existance // check variable existance
variable, err = h.readDB.GetVariableByName(tx, parentID, variableName) variable, err = h.readDB.GetVariableByName(tx, parentID, variableName)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
if variable == nil { if variable == nil {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable with name %q doesn't exist", variableName)) 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)} cgNames := []string{util.EncodeSha256Hex("variableid-" + variable.ID)}
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
actions := []*datamanager.Action{ actions := []*datamanager.Action{
@ -251,5 +252,5 @@ func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.Con
} }
_, err = h.dm.WriteWal(ctx, actions, cgt) _, err = h.dm.WriteWal(ctx, actions, cgt)
return err return errors.WithStack(err)
} }

View File

@ -18,11 +18,11 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"agola.io/agola/internal/errors"
"agola.io/agola/internal/util" "agola.io/agola/internal/util"
"agola.io/agola/services/configstore/types" "agola.io/agola/services/configstore/types"
"github.com/gorilla/mux" "github.com/gorilla/mux"
errors "golang.org/x/xerrors"
) )
type ErrorResponse struct { type ErrorResponse struct {
@ -33,7 +33,7 @@ func GetConfigTypeRef(r *http.Request) (types.ConfigType, string, error) {
vars := mux.Vars(r) vars := mux.Vars(r)
projectRef, err := url.PathUnescape(vars["projectref"]) projectRef, err := url.PathUnescape(vars["projectref"])
if err != nil { 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 != "" { if projectRef != "" {
return types.ConfigTypeProject, projectRef, nil return types.ConfigTypeProject, projectRef, nil
@ -41,7 +41,7 @@ func GetConfigTypeRef(r *http.Request) (types.ConfigType, string, error) {
projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"])
if err != nil { 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 != "" { if projectGroupRef != "" {
return types.ConfigTypeProjectGroup, projectGroupRef, nil return types.ConfigTypeProjectGroup, projectGroupRef, nil

Some files were not shown because too many files have changed in this diff Show More