Skip to content

Commit

Permalink
Merge branch 'v3' into dependabot/go_modules/golang.org/x/tools-0.24.0
Browse files Browse the repository at this point in the history
  • Loading branch information
raphael authored Aug 14, 2024
2 parents eecedd5 + 7a9bc7a commit 5dd0997
Show file tree
Hide file tree
Showing 51 changed files with 260 additions and 302 deletions.
4 changes: 2 additions & 2 deletions cmd/goa/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type Generator struct {
}

// NewGenerator creates a Generator.
func NewGenerator(cmd string, path, output string) *Generator {
func NewGenerator(cmd, path, output string) *Generator {
bin := "goa"
if runtime.GOOS == "windows" {
bin += ".exe"
Expand Down Expand Up @@ -247,7 +247,7 @@ func (g *Generator) runGoCmd(args ...string) error {
out, err := c.CombinedOutput()
if err != nil {
if len(out) > 0 {
return fmt.Errorf(string(out))
return fmt.Errorf("%s", out)
}
return fmt.Errorf("failed to compile generator: %w", err)
}
Expand Down
4 changes: 4 additions & 0 deletions dsl/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ func Field(tag any, name string, args ...any) {
// })
// })
func OneOf(name string, args ...any) {
if len(args) == 0 {
eval.TooFewArgError()
return
}
if len(args) > 2 {
eval.TooManyArgError()
return
Expand Down
1 change: 1 addition & 0 deletions dsl/result_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ func ResultType(identifier string, args ...any) *expr.ResultTypeExpr {
}
// Add the type to the generated types root for later evaluation.
rt := expr.NewResultTypeExpr(typeName, identifier, fn)
rt.Meta = expr.MetaExpr{"openapi:typename": []string{typeName}}
expr.Root.ResultTypes = append(expr.Root.ResultTypes, rt)

return rt
Expand Down
8 changes: 6 additions & 2 deletions dsl/user_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,12 @@ func Type(name string, args ...any) expr.UserType {
}

t := &expr.UserTypeExpr{
TypeName: name,
AttributeExpr: &expr.AttributeExpr{Type: base, DSLFunc: fn},
TypeName: name,
AttributeExpr: &expr.AttributeExpr{
Type: base,
DSLFunc: fn,
Meta: expr.MetaExpr{"openapi:typename": []string{name}},
},
}
expr.Root.Types = append(expr.Root.Types, t)
return t
Expand Down
1 change: 1 addition & 0 deletions eval/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func TestTooFewArgError(t *testing.T) {
"ErrorName": func() { ErrorName() },
"ErrorName (int)": func() { Type("name", func() { ErrorName(1) }) },
"Example": func() { Example() },
"OneOf": func() { OneOf("name") },
"Response (grpc)": func() { Service("s", func() { GRPC(func() { Response("name") }) }) },
"Response (http)": func() { Service("s", func() { HTTP(func() { Response("name") }) }) },
}
Expand Down
2 changes: 1 addition & 1 deletion expr/grpc_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ service "Service" gRPC endpoint "Method": field number 2 in attribute "key_dup_i
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
if c.Errors == nil || len(c.Errors) == 0 {
if len(c.Errors) == 0 {
expr.RunDSL(t, c.DSL)
} else {
var errs []error
Expand Down
4 changes: 2 additions & 2 deletions expr/http_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ func (r *HTTPResponseExpr) Validate(e *HTTPEndpointExpr) *eval.ValidationErrors
// an explicit conflict with the content-type and response.
if (r.ContentType == "text/html" || r.ContentType == "text/plain") && !e.SkipRequestBodyEncodeDecode {
if e.MethodExpr.Result.Type != nil && e.MethodExpr.Result.Type != String && e.MethodExpr.Result.Type != Bytes && r.Body == nil {
verr.Add(r, fmt.Sprintf("Result type must be String or Bytes when ContentType is '%s'", r.ContentType))
verr.Add(r, "Result type must be String or Bytes when ContentType is '%s'", r.ContentType)
}
if r.Body != nil && r.Body.Type != String && r.Body.Type != Bytes {
verr.Add(r, fmt.Sprintf("Result type must be String or Bytes when ContentType is '%s'", r.ContentType))
verr.Add(r, "Result type must be String or Bytes when ContentType is '%s'", r.ContentType)
}
}

Expand Down
23 changes: 10 additions & 13 deletions grpc/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func NewErrorResponse(err error) *goapb.ErrorResponse {
Fault: gerr.Fault,
}
}
return NewErrorResponse(goa.Fault(err.Error()))
return NewErrorResponse(goa.Fault("%s", err.Error()))
}

// NewServiceError returns a goa ServiceError type for the given ErrorResponse
Expand Down Expand Up @@ -92,18 +92,15 @@ func EncodeError(err error) error {
if errors.As(err, &gerr) {
// goa service error type. Compute the status code from the service error
// characteristics and create a new detailed gRPC status error.
var code codes.Code
{
code = codes.Unknown
if gerr.Fault {
code = codes.Internal
}
if gerr.Timeout {
code = codes.DeadlineExceeded
}
if gerr.Temporary {
code = codes.Unavailable
}
code := codes.Unknown
if gerr.Fault {
code = codes.Internal
}
if gerr.Timeout {
code = codes.DeadlineExceeded
}
if gerr.Temporary {
code = codes.Unavailable
}
return NewStatusError(code, err, NewErrorResponse(err))
}
Expand Down
95 changes: 29 additions & 66 deletions http/codegen/openapi/v2/files_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/getkin/kin-openapi/openapi2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

httpgen "goa.design/goa/v3/http/codegen"
"goa.design/goa/v3/http/codegen/openapi"
Expand Down Expand Up @@ -99,15 +100,15 @@ func TestSections(t *testing.T) {
t.Fatalf("failed to read golden file: %s", err)
}
if !bytes.Equal(buf.Bytes(), want) {
var left, right string
var got, expected string
if filepath.Ext(o.Path) == ".json" {
left = prettifyJSON(t, buf.Bytes())
right = prettifyJSON(t, want)
got = prettifyJSON(t, buf.Bytes())
expected = prettifyJSON(t, want)
} else {
left = buf.String()
right = string(want)
got = buf.String()
expected = string(want)
}
assert.Equal(t, left, right)
assert.Equal(t, expected, got)
}
})
}
Expand Down Expand Up @@ -145,51 +146,32 @@ func TestValidations(t *testing.T) {
openapi.Definitions = make(map[string]*openapi.Schema)
root := httpgen.RunHTTPDSL(t, c.DSL)
oFiles, err := openapiv2.Files(root)
if err != nil {
t.Fatalf("OpenAPI failed with %s", err)
}
if len(oFiles) == 0 {
t.Fatalf("No swagger files")
}
require.NoError(t, err, "OpenAPI failed")
require.NotEmpty(t, oFiles, "No swagger files")
for i, o := range oFiles {
tname := fmt.Sprintf("file%d", i)
s := o.SectionTemplates
t.Run(tname, func(t *testing.T) {
if len(s) != 1 {
t.Fatalf("expected 1 section, got %d", len(s))
}
if s[0].Source == "" {
t.Fatalf("empty section template")
}
if s[0].Data == nil {
t.Fatalf("nil data")
}
require.Len(t, s, 1, "expected 1 section, got %d", len(s))
require.NotEmpty(t, s[0].Source, "empty section template")
require.NotNil(t, s[0].Data, "nil data")
var buf bytes.Buffer
tmpl := template.Must(template.New("openapi").Funcs(s[0].FuncMap).Parse(s[0].Source))
if err := tmpl.Execute(&buf, s[0].Data); err != nil {
t.Fatalf("failed to render template: %s", err)
}
require.NoError(t, tmpl.Execute(&buf, s[0].Data), "failed to render template")
if filepath.Ext(o.Path) == ".json" {
if err := validateSwagger(buf.Bytes()); err != nil {
t.Fatalf("invalid swagger: %s", err)
}
require.NoError(t, validateSwagger(buf.Bytes()), "invalid swagger")
}

golden := filepath.Join(goldenPath, fmt.Sprintf("%s_%s.golden", c.Name, tname))
if *update {
if err := os.WriteFile(golden, buf.Bytes(), 0644); err != nil {
t.Fatalf("failed to update golden file: %s", err)
}
require.NoError(t, os.WriteFile(golden, buf.Bytes(), 0644), "failed to update golden file")
return
}

want, err := os.ReadFile(golden)
require.NoError(t, err, "failed to read golden file")
want = bytes.ReplaceAll(want, []byte{'\r', '\n'}, []byte{'\n'})
if err != nil {
t.Fatalf("failed to read golden file: %s", err)
}
if !bytes.Equal(buf.Bytes(), want) {
t.Errorf("result do not match the golden file:\n--BEGIN--\n%s\n--END--\n", buf.Bytes())
}
assert.Equal(t, string(want), buf.String())
})
}
})
Expand All @@ -212,51 +194,32 @@ func TestExtensions(t *testing.T) {
openapi.Definitions = make(map[string]*openapi.Schema)
root := httpgen.RunHTTPDSL(t, c.DSL)
oFiles, err := openapiv2.Files(root)
if err != nil {
t.Fatalf("OpenAPI failed with %s", err)
}
if len(oFiles) == 0 {
t.Fatalf("No swagger files")
}
require.NoError(t, err, "OpenAPI failed")
require.NotEmpty(t, oFiles, "No swagger files")
for i, o := range oFiles {
tname := fmt.Sprintf("file%d", i)
s := o.SectionTemplates
t.Run(tname, func(t *testing.T) {
if len(s) != 1 {
t.Fatalf("expected 1 section, got %d", len(s))
}
if s[0].Source == "" {
t.Fatalf("empty section template")
}
if s[0].Data == nil {
t.Fatalf("nil data")
}
require.Len(t, s, 1, "expected 1 section, got %d", len(s))
require.NotEmpty(t, s[0].Source, "empty section template")
require.NotNil(t, s[0].Data, "nil data")
var buf bytes.Buffer
tmpl := template.Must(template.New("openapi").Funcs(s[0].FuncMap).Parse(s[0].Source))
if err := tmpl.Execute(&buf, s[0].Data); err != nil {
t.Fatalf("failed to render template: %s", err)
}
require.NoError(t, tmpl.Execute(&buf, s[0].Data), "failed to render template")
if filepath.Ext(o.Path) == ".json" {
if err := validateSwagger(buf.Bytes()); err != nil {
t.Fatalf("invalid swagger: %s", err)
}
require.NoError(t, validateSwagger(buf.Bytes()), "invalid swagger")
}

golden := filepath.Join(goldenPath, fmt.Sprintf("%s_%s.golden", c.Name, tname))
if *update {
if err := os.WriteFile(golden, buf.Bytes(), 0644); err != nil {
t.Fatalf("failed to update golden file: %s", err)
}
require.NoError(t, os.WriteFile(golden, buf.Bytes(), 0644), "failed to update golden file")
return
}

want, err := os.ReadFile(golden)
want = bytes.ReplaceAll(want, []byte{'\r', '\n'}, []byte{'\n'})
if err != nil {
t.Fatalf("failed to read golden file: %s", err)
}
if !bytes.Equal(buf.Bytes(), want) {
t.Errorf("result do not match the golden file:\n--BEGIN--\n%s\n--END--\n", buf.Bytes())
}
require.NoError(t, err, "failed to read golden file")
assert.Equal(t, string(want), buf.String())
})
}
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"swagger":"2.0","info":{"title":"","version":"0.0.1","x-test-api":"API"},"host":"goa.design","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/":{"post":{"operationId":"testService#testEndpoint","parameters":[{"in":"body","name":"TestEndpointRequestBody","required":true,"schema":{"$ref":"#/definitions/TestServiceTestEndpointRequestBody"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TestServiceTestEndpointResponseBody"}}},"schemes":["https"],"summary":"testEndpoint testService","tags":["testService"],"x-test-operation":"Operation"},"x-test-foo":"bar"}},"definitions":{"TestServiceTestEndpointRequestBody":{"title":"TestServiceTestEndpointRequestBody","type":"object","properties":{"string":{"example":"","type":"string","x-test-schema":"Payload"}},"example":{"string":""}},"TestServiceTestEndpointResponseBody":{"title":"TestServiceTestEndpointResponseBody","type":"object","properties":{"string":{"example":"","type":"string","x-test-schema":"Result"}},"example":{"string":""}}},"tags":[{"description":"Description of Backend","externalDocs":{"description":"See more docs here","url":"http://example.com"},"name":"Backend","x-data":{"foo":"bar"}}]}
{"swagger":"2.0","info":{"title":"","version":"0.0.1","x-test-api":"API"},"host":"goa.design","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/":{"post":{"operationId":"testService#testEndpoint","parameters":[{"in":"body","name":"TestEndpointRequestBody","required":true,"schema":{"$ref":"#/definitions/Payload"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/Result"}}},"schemes":["https"],"summary":"testEndpoint testService","tags":["testService"],"x-test-operation":"Operation"},"x-test-foo":"bar"}},"definitions":{"Payload":{"title":"Payload","type":"object","properties":{"string":{"example":"","type":"string","x-test-schema":"Payload"}},"example":{"string":""}},"Result":{"title":"Result","type":"object","properties":{"string":{"example":"","type":"string","x-test-schema":"Result"}},"example":{"string":""}}},"tags":[{"description":"Description of Backend","externalDocs":{"description":"See more docs here","url":"http://example.com"},"name":"Backend","x-data":{"foo":"bar"}}]}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ paths:
name: TestEndpointRequestBody
required: true
schema:
$ref: '#/definitions/TestServiceTestEndpointRequestBody'
$ref: '#/definitions/Payload'
responses:
"200":
description: OK response.
schema:
$ref: '#/definitions/TestServiceTestEndpointResponseBody'
$ref: '#/definitions/Result'
schemes:
- https
summary: testEndpoint testService
Expand All @@ -35,8 +35,8 @@ paths:
x-test-operation: Operation
x-test-foo: bar
definitions:
TestServiceTestEndpointRequestBody:
title: TestServiceTestEndpointRequestBody
Payload:
title: Payload
type: object
properties:
string:
Expand All @@ -45,8 +45,8 @@ definitions:
x-test-schema: Payload
example:
string: ""
TestServiceTestEndpointResponseBody:
title: TestServiceTestEndpointResponseBody
Result:
title: Result
type: object
properties:
string:
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"swagger":"2.0","info":{"title":"","version":"0.0.1"},"host":"goa.design","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/":{"get":{"tags":["testService"],"summary":"testEndpoint testService","operationId":"testService#testEndpoint","parameters":[{"name":"TestEndpointRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/TestServiceTestEndpointRequestBody"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TestServiceTestEndpointResponseBody"}}},"schemes":["https"]},"post":{"tags":["anotherTestService"],"summary":"testEndpoint anotherTestService","operationId":"anotherTestService#testEndpoint","parameters":[{"name":"TestEndpointRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/AnotherTestServiceTestEndpointRequestBody"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/AnotherTestServiceTestEndpointResponseBody"}}},"schemes":["https"]}}},"definitions":{"AnotherTestServiceTestEndpointRequestBody":{"title":"AnotherTestServiceTestEndpointRequestBody","type":"object","properties":{"string":{"type":"string","example":""}},"example":{"string":""}},"AnotherTestServiceTestEndpointResponseBody":{"title":"AnotherTestServiceTestEndpointResponseBody","type":"object","properties":{"string":{"type":"string","example":""}},"example":{"string":""}},"TestServiceTestEndpointRequestBody":{"title":"TestServiceTestEndpointRequestBody","type":"object","properties":{"string":{"type":"string","example":""}},"example":{"string":""}},"TestServiceTestEndpointResponseBody":{"title":"TestServiceTestEndpointResponseBody","type":"object","properties":{"string":{"type":"string","example":""}},"example":{"string":""}}}}
{"swagger":"2.0","info":{"title":"","version":"0.0.1"},"host":"goa.design","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/":{"get":{"tags":["testService"],"summary":"testEndpoint testService","operationId":"testService#testEndpoint","parameters":[{"name":"TestEndpointRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/Payload"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/Result"}}},"schemes":["https"]},"post":{"tags":["anotherTestService"],"summary":"testEndpoint anotherTestService","operationId":"anotherTestService#testEndpoint","parameters":[{"name":"TestEndpointRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/Payload"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/Result"}}},"schemes":["https"]}}},"definitions":{"Payload":{"title":"Payload","type":"object","properties":{"string":{"type":"string","example":""}},"example":{"string":""}},"Result":{"title":"Result","type":"object","properties":{"string":{"type":"string","example":""}},"example":{"string":""}}}}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ paths:
in: body
required: true
schema:
$ref: '#/definitions/TestServiceTestEndpointRequestBody'
$ref: '#/definitions/Payload'
responses:
"200":
description: OK response.
schema:
$ref: '#/definitions/TestServiceTestEndpointResponseBody'
$ref: '#/definitions/Result'
schemes:
- https
post:
Expand All @@ -41,44 +41,26 @@ paths:
in: body
required: true
schema:
$ref: '#/definitions/AnotherTestServiceTestEndpointRequestBody'
$ref: '#/definitions/Payload'
responses:
"200":
description: OK response.
schema:
$ref: '#/definitions/AnotherTestServiceTestEndpointResponseBody'
$ref: '#/definitions/Result'
schemes:
- https
definitions:
AnotherTestServiceTestEndpointRequestBody:
title: AnotherTestServiceTestEndpointRequestBody
Payload:
title: Payload
type: object
properties:
string:
type: string
example: ""
example:
string: ""
AnotherTestServiceTestEndpointResponseBody:
title: AnotherTestServiceTestEndpointResponseBody
type: object
properties:
string:
type: string
example: ""
example:
string: ""
TestServiceTestEndpointRequestBody:
title: TestServiceTestEndpointRequestBody
type: object
properties:
string:
type: string
example: ""
example:
string: ""
TestServiceTestEndpointResponseBody:
title: TestServiceTestEndpointResponseBody
Result:
title: Result
type: object
properties:
string:
Expand Down
Loading

0 comments on commit 5dd0997

Please sign in to comment.