Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add strict yaml unmarshal option #90

Merged
merged 2 commits into from
Feb 16, 2024

Conversation

DannyBrito
Copy link
Contributor

This PR adds strict option for yaml unmarshal, any unknow field or typo field in a dalec spec will result in error
This should solve Issue #81

example output when trying to build example with unknow field.

go-md2man-2.yml:1
--------------------
   1 | >>> # syntax=local/dalec/frontend:latest
   2 |     name: go-md2man
   3 |     version: 2.0.3
--------------------
ERROR: failed to solve: error loading spec: error unmarshalling spec: [9:1] unknown field "fake-field"
       6 | license: MIT
       7 | description: A tool to convert markdown into man pages (roff).
       8 | website: https://github.com/cpuguy83/go-md2man
    >  9 | fake-field: test
           ^
      10 | sources:
      11 |   src:
      12 |     git:

@pmengelbert
Copy link
Contributor

I think there's errors in some of the test fixtures. That's causing them to not unmarshal in strict mode -- which is why it's good to have this change.

@DannyBrito
Copy link
Contributor Author

DannyBrito commented Feb 6, 2024

I looked at what is going on here and this might be a hierarchy problem when doing the unmarshall of the Spec, and this is why when unmarshalling it's not recognizing CheckOutput with TestStep. Could someone please help me validate this?

type Spec struct {
  // ...
  Tests []*TestSpec `yaml:"tests,omitempty" json:"tests,omitempty"`
}

type TestSpec struct {
  Name    string `yaml:"name" json:"name" jsonschema:"required"`
 // Seems like this might be taking presendece over TestStep
  Command `yaml:",inline"`
  Steps []TestStep `yaml:"steps" json:"steps" jsonschema:"required"`
}

type Command struct {
  // ...
  // Steps - as BuildStep instead of TestStep
  Steps []*BuildStep `yaml:"steps" json:"steps" jsonschema:"required"`
}

// TestStep is a wrapper for [BuildStep] to include checks on stdio streams
type TestStep struct {
  BuildStep `yaml:",inline"`
  // Stdout is the expected output on stdout
  Stdout CheckOutput `yaml:"stdout,omitempty" json:"stdout,omitempty"`
  // Stderr is the expected output on stderr
  Stderr CheckOutput `yaml:"stderr,omitempty" json:"stderr,omitempty"`
  // Stdin is the input to pass to stdin for the command
  Stdin string `yaml:"stdin,omitempty" json:"stdin,omitempty"`
}

Seems as we are embedding Command struct in TestSpec the Steps field in command struct is taking precedence, so it is of type BuildStep instead of the explict field Steps as TestStep wrapper

@cpuguy83
Copy link
Member

cpuguy83 commented Feb 6, 2024

The weird thing is, that is a valid field.

@DannyBrito
Copy link
Contributor Author

DannyBrito commented Feb 7, 2024

@adamperlin and I had the change to explore this issue a bit more, here is some of the behavior we saw:

TestSpec struct is conflicting during unmarshall, as it is embedded with fields from Command which has an existing Steps field of type []*BuildStep but TestSpec also has explicit written field Steps of type []TestStep.

Unmarshalling behavior without Strict gives precedence to Steps field declared within the TestSpec instead of Steps field embedded in Command effectively making it of type []TestStep.

The observed behavior with Strict is to not recognize the Steps field causing it to fail. So really sure if this is part of the intended behavior of the library or is a bug.

One question about the TestSpec, is the embedded fields from Command Struct ever used? If not, maybe we could do some clean-up of this TestSpec struct and can prevent this issue?

@adamperlin
Copy link
Contributor

Just to add on to what Danny said, if we add an omitempty tag to the embedded Command this issue is resolved for now. If the embedded Command is required, then if a command is NOT specified, in strict mode the unmarshaler will always try and unmarshal a Command, which will partly work if a TestSpec is present due to the steps key being in the yaml for both Command and TestSpec. It will confusingly fail on fields such as stdout, etc. which are specific to TestSpec, which seems to be what happened here.

What was the original purpose for embedded Command?

@cpuguy83
Copy link
Member

cpuguy83 commented Feb 7, 2024

wrt embedded:

I wonder if we can use yaml:",inline" but without embedding in go? (but this is just a side note to investigate)
That said, it looks like we've got some structs that need to be split out (or fields duplicated, which is ok).

@DannyBrito DannyBrito force-pushed the dannybrito/strict-unmarshal branch 7 times, most recently from 86419e8 to e3f4947 Compare February 15, 2024 18:34
Copy link
Member

@cpuguy83 cpuguy83 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor change, and I opened #138 to deal with the command stuff.
I think we just should not inline these data types, its too confusing.

load_test.go Outdated
// NOTE: not using text template yaml for this test
// tabs seem to be illegal in yaml indentation
// yaml unmarshalling with strict mode doesn't produce a great error message.
yaml, err := os.ReadFile("test/fixtures/unmarshall/source-inline.yml")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use //go:embed instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case you haven't seen that before: https://pkg.go.dev/embed

@DannyBrito DannyBrito force-pushed the dannybrito/strict-unmarshal branch from e3f4947 to 4ad6b31 Compare February 16, 2024 17:58
@DannyBrito DannyBrito requested a review from cpuguy83 February 16, 2024 18:53
@cpuguy83 cpuguy83 merged commit ac2a8cc into Azure:main Feb 16, 2024
9 checks passed
@DannyBrito DannyBrito deleted the dannybrito/strict-unmarshal branch March 28, 2024 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants