Skip to content

Commit

Permalink
fix: marshalling of fallback code samples
Browse files Browse the repository at this point in the history
  • Loading branch information
mfbx9da4 committed Jul 1, 2024
1 parent 5d8e0e0 commit b95f0a2
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 53 deletions.
66 changes: 50 additions & 16 deletions workflow/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,29 @@ type Overlay struct {
}

func (o *Overlay) UnmarshalYAML(unmarshal func(interface{}) error) error {
var doc Document
if err := unmarshal(&doc); err == nil {
o.Document = &doc
// Overlay is flat, so we need to unmarshal it into a map to determine if it's a document or fallbackCodeSamples
var overlayMap map[string]interface{}
if err := unmarshal(&overlayMap); err != nil {
return err
}

if _, ok := overlayMap["fallbackCodeSamplesLanguage"]; ok {
var fallbackCodeSamples FallbackCodeSamples
if err := unmarshal(&fallbackCodeSamples); err != nil {
return err
}

o.FallbackCodeSamples = &fallbackCodeSamples
return nil
}

var fallback FallbackCodeSamples
if err := unmarshal(&fallback); err == nil {
o.FallbackCodeSamples = &fallback
if _, ok := overlayMap["location"]; ok {
var document Document
if err := unmarshal(&document); err != nil {
return err
}

o.Document = &document
return nil
}

Expand Down Expand Up @@ -95,16 +109,8 @@ func (s Source) Validate() error {
}

for i, overlay := range s.Overlays {
if overlay.Document != nil {
if err := overlay.Document.Validate(); err != nil {
return fmt.Errorf("failed to validate overlay document %d: %w", i, err)
}
}

if overlay.FallbackCodeSamples != nil {
if overlay.FallbackCodeSamples.FallbackCodeSamplesLanguage == "" {
return fmt.Errorf("fallbackCodeSamplesLanguage is required")
}
if err := overlay.Validate(); err != nil {
return fmt.Errorf("failed to validate overlay %d: %w", i, err)
}
}

Expand Down Expand Up @@ -200,6 +206,34 @@ func (d Document) IsSpeakeasyRegistry() bool {
return strings.Contains(d.Location, "registry.speakeasyapi.dev")
}

func (f FallbackCodeSamples) Validate() error {
if f.FallbackCodeSamplesLanguage == "" {
return fmt.Errorf("fallbackCodeSamplesLanguage is required")
}

return nil
}

func (o Overlay) Validate() error {
if o.Document != nil {
if err := o.Document.Validate(); err != nil {
return fmt.Errorf("failed to validate overlay document: %w", err)
}
}

if o.FallbackCodeSamples != nil {
if err := o.FallbackCodeSamples.Validate(); err != nil {
return fmt.Errorf("failed to validate overlay fallbackCodeSamples: %w", err)
}
}

if o.Document == nil && o.FallbackCodeSamples == nil {
return fmt.Errorf("overlay must have either a document or fallbackCodeSamples")
}

return nil
}

// Parse the location to extract the namespace ID, namespace name, and reference
// The location should be in the format registry.speakeasyapi.dev/org/workspace/name[:tag|@sha256:digest]
func ParseSpeakeasyRegistryReference(location string) *SpeakeasyRegistryDocument {
Expand Down
117 changes: 80 additions & 37 deletions workflow/source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/speakeasy-api/sdk-gen-config/workflow"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

func TestSource_Validate(t *testing.T) {
Expand Down Expand Up @@ -111,13 +112,9 @@ func TestSource_Validate(t *testing.T) {
},
},
},
Overlays: []workflow.Document{
{
Location: "overlay.yaml",
},
{
Location: "http://example.com/overlay.yaml",
},
Overlays: []workflow.Overlay{
{Document: &workflow.Document{Location: "overlay.yaml"}},
{Document: &workflow.Document{Location: "http://example.com/overlay.yaml"}},
},
Output: pointer.ToString("openapi.yaml"),
},
Expand All @@ -133,13 +130,9 @@ func TestSource_Validate(t *testing.T) {
Location: "openapi.yaml",
},
},
Overlays: []workflow.Document{
{
Location: "overlay.yaml",
},
{
Location: "overlay.yaml",
},
Overlays: []workflow.Overlay{
{Document: &workflow.Document{Location: "overlay.yaml"}},
{Document: &workflow.Document{Location: "overlay.yaml"}},
},
Output: pointer.ToString("openapi.json"),
},
Expand All @@ -158,10 +151,8 @@ func TestSource_Validate(t *testing.T) {
Location: "openapi.yaml",
},
},
Overlays: []workflow.Document{
{
Location: "overlay.yaml",
},
Overlays: []workflow.Overlay{
{Document: &workflow.Document{Location: "overlay.yaml"}},
},
Output: pointer.ToString("openapi.json"),
},
Expand All @@ -173,10 +164,8 @@ func TestSource_Validate(t *testing.T) {
args: args{
source: workflow.Source{
Inputs: []workflow.Document{},
Overlays: []workflow.Document{
{
Location: "overlay.yaml",
},
Overlays: []workflow.Overlay{
{Document: &workflow.Document{Location: "overlay.yaml"}},
},
},
},
Expand Down Expand Up @@ -236,12 +225,45 @@ func TestSource_Validate(t *testing.T) {
Location: "openapi.yaml",
},
},
Overlays: []workflow.Document{
{},
Overlays: []workflow.Overlay{{
Document: &workflow.Document{},
}},
},
},
wantErr: fmt.Errorf("failed to validate overlay 0: failed to validate overlay document: location is required"),
},
{
name: "overlay fails with no fallbackCodeSamplesLanguage",
args: args{
source: workflow.Source{
Inputs: []workflow.Document{
{
Location: "openapi.yaml",
},
},
Overlays: []workflow.Overlay{{
FallbackCodeSamples: &workflow.FallbackCodeSamples{},
}},
},
},
wantErr: fmt.Errorf("failed to validate overlay 0: failed to validate overlay fallbackCodeSamples: fallbackCodeSamplesLanguage is required"),
},
{
name: "overlay with fallbackCodeSamplesLanguage",
args: args{
source: workflow.Source{
Inputs: []workflow.Document{
{
Location: "openapi.yaml",
},
},
Overlays: []workflow.Overlay{{
FallbackCodeSamples: &workflow.FallbackCodeSamples{
FallbackCodeSamplesLanguage: "python",
},
}},
},
},
wantErr: fmt.Errorf("failed to validate overlay 0: location is required"),
},
{
name: "registry success",
Expand Down Expand Up @@ -306,6 +328,29 @@ func TestSource_Validate(t *testing.T) {
} else {
assert.NoError(t, err)
}

if tt.wantErr == nil {
// Marshal to yaml
w := workflow.Workflow{
Version: workflow.WorkflowVersion,
SpeakeasyVersion: "latest",
Sources: map[string]workflow.Source{
"source": tt.args.source,
},
}
data, err := yaml.Marshal(w)
require.NoError(t, err)

// Unmarshal yaml
var w2 workflow.Workflow
err = yaml.Unmarshal(data, &w2)
require.NoError(t, err)

// Validate
err = w2.Validate([]string{})

assert.NoError(t, err)
}
})
}
}
Expand Down Expand Up @@ -404,10 +449,8 @@ func TestSource_GetOutputLocation(t *testing.T) {
Location: "openapi.yaml",
},
},
Overlays: []workflow.Document{
{
Location: "overlay.yaml",
},
Overlays: []workflow.Overlay{
{Document: &workflow.Document{Location: "overlay.yaml"}},
},
Output: pointer.ToString("processed.yaml"),
},
Expand All @@ -423,10 +466,8 @@ func TestSource_GetOutputLocation(t *testing.T) {
Location: "openapi.yaml",
},
},
Overlays: []workflow.Document{
{
Location: "overlay.yaml",
},
Overlays: []workflow.Overlay{
{Document: &workflow.Document{Location: "overlay.yaml"}},
},
},
},
Expand Down Expand Up @@ -553,10 +594,12 @@ func createLocalFiles(s workflow.Source) (string, error) {
}

for _, overlay := range s.Overlays {
_, err := url.ParseRequestURI(overlay.Location)
if err != nil {
if err := createEmptyFile(filepath.Join(tmpDir, overlay.Location)); err != nil {
return "", err
if overlay.Document != nil {
_, err := url.ParseRequestURI(overlay.Document.Location)
if err != nil {
if err := createEmptyFile(filepath.Join(tmpDir, overlay.Document.Location)); err != nil {
return "", err
}
}
}
}
Expand Down

0 comments on commit b95f0a2

Please sign in to comment.