Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
Remove duplication in ChangesetSpec/CampaignSpec.UnmarshalValidate (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mrnugget committed Jul 20, 2020
1 parent eb6570a commit 20a22fb
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 61 deletions.
106 changes: 46 additions & 60 deletions internal/campaigns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/sourcegraph/sourcegraph/internal/extsvc/bitbucketserver"
"github.com/sourcegraph/sourcegraph/internal/extsvc/github"
"github.com/sourcegraph/sourcegraph/internal/extsvc/gitlab"
"github.com/sourcegraph/sourcegraph/internal/jsonc"
"github.com/sourcegraph/sourcegraph/internal/vcs/git"
"github.com/sourcegraph/sourcegraph/schema"
"github.com/xeipuuv/gojsonschema"
Expand Down Expand Up @@ -1671,36 +1670,7 @@ func (cs *CampaignSpec) Clone() *CampaignSpec {
// UnmarshalValidate unmarshals the RawSpec into Spec and validates it against
// the CampaignSpec schema and does additional semantic validation.
func (cs *CampaignSpec) UnmarshalValidate() error {
sl := gojsonschema.NewSchemaLoader()
sc, err := sl.Compile(gojsonschema.NewStringLoader(schema.CampaignSpecSchemaJSON))
if err != nil {
return errors.Wrap(err, "failed to compile CampaignSpec JSON schema")
}

normalized, err := yaml.YAMLToJSONCustom([]byte(cs.RawSpec), yamlv3.Unmarshal)
if err != nil {
return errors.Wrapf(err, "failed to normalize JSON")
}

res, err := sc.Validate(gojsonschema.NewBytesLoader(normalized))
if err != nil {
return errors.Wrap(err, "failed to validate CampaignSpec against schema")
}

var errs *multierror.Error
for _, err := range res.Errors() {
e := err.String()
// Remove `(root): ` from error formatting since these errors are
// presented to users.
e = strings.TrimPrefix(e, "(root): ")
errs = multierror.Append(errs, errors.New(e))
}

if err := json.Unmarshal(normalized, &cs.Spec); err != nil {
errs = multierror.Append(errs, err)
}

return errs.ErrorOrNil()
return unmarshalValidate(schema.CampaignSpecSchemaJSON, []byte(cs.RawSpec), &cs.Spec)
}

type CampaignSpecFields struct {
Expand Down Expand Up @@ -1765,45 +1735,25 @@ func (cs *ChangesetSpec) Clone() *ChangesetSpec {
// UnmarshalValidate unmarshals the RawSpec into Spec and validates it against
// the ChangesetSpec schema and does additional semantic validation.
func (cs *ChangesetSpec) UnmarshalValidate() error {
sl := gojsonschema.NewSchemaLoader()
sc, err := sl.Compile(gojsonschema.NewStringLoader(schema.ChangesetSpecSchemaJSON))
if err != nil {
return errors.Wrap(err, "failed to compile ChangesetSpec JSON schema")
}

normalized, err := jsonc.Parse(cs.RawSpec)
err := unmarshalValidate(schema.ChangesetSpecSchemaJSON, []byte(cs.RawSpec), &cs.Spec)
if err != nil {
return errors.Wrapf(err, "failed to normalize JSON")
}

res, err := sc.Validate(gojsonschema.NewBytesLoader(normalized))
if err != nil {
return errors.Wrap(err, "failed to validate ChangesetSpec against schema")
}

var errs *multierror.Error
for _, err := range res.Errors() {
e := err.String()
// Remove `(root): ` from error formatting since these errors are
// presented to users.
e = strings.TrimPrefix(e, "(root): ")
errs = multierror.Append(errs, errors.New(e))
}

if err := json.Unmarshal(normalized, &cs.Spec); err != nil {
errs = multierror.Append(errs, err)
return errs.ErrorOrNil()
return err
}

headRepo := cs.Spec.HeadRepository
baseRepo := cs.Spec.BaseRepository
if headRepo != "" && baseRepo != "" && headRepo != baseRepo {
errs = multierror.Append(errs, errors.New("headRepository does not match baseRepository"))
return ErrHeadBaseMismatch
}

return errs.ErrorOrNil()
return nil
}

// ErrHeadBaseMismatch is returned by (*ChangesetSpec).UnmarshalValidate() if
// the head and base repositories do not match (a case which we do not support
// yet).
var ErrHeadBaseMismatch = errors.New("headRepository does not match baseRepository")

type ChangesetSpecDescription struct {
BaseRepository graphql.ID `json:"baseRepository,omitempty"`

Expand All @@ -1830,3 +1780,39 @@ type GitCommitDescription struct {
Message string `json:"message,omitempty"`
Diff string `json:"diff,omitempty"`
}

// unmarshalValidate validates the input, which can be YAML or JSON, against
// the provided JSON schema. If the validation is successful is unmarshals the
// validated input into the target.
func unmarshalValidate(schema string, input []byte, target interface{}) error {
sl := gojsonschema.NewSchemaLoader()
sc, err := sl.Compile(gojsonschema.NewStringLoader(schema))
if err != nil {
return errors.Wrap(err, "failed to compile JSON schema")
}

normalized, err := yaml.YAMLToJSONCustom(input, yamlv3.Unmarshal)
if err != nil {
return errors.Wrapf(err, "failed to normalize JSON")
}

res, err := sc.Validate(gojsonschema.NewBytesLoader(normalized))
if err != nil {
return errors.Wrap(err, "failed to validate input against schema")
}

var errs *multierror.Error
for _, err := range res.Errors() {
e := err.String()
// Remove `(root): ` from error formatting since these errors are
// presented to users.
e = strings.TrimPrefix(e, "(root): ")
errs = multierror.Append(errs, errors.New(e))
}

if err := json.Unmarshal(normalized, target); err != nil {
errs = multierror.Append(errs, err)
}

return errs.ErrorOrNil()
}
2 changes: 1 addition & 1 deletion internal/campaigns/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,7 @@ func TestChangesetSpecUnmarshalValidate(t *testing.T) {
"diff": "the diff"
}]
}`,
err: "1 error occurred:\n\t* headRepository does not match baseRepository\n\n",
err: ErrHeadBaseMismatch.Error(),
},
{
name: "too many commits in GitBranchChangesetDescription",
Expand Down

0 comments on commit 20a22fb

Please sign in to comment.