Skip to content

Commit 0df0530

Browse files
authored
Merge branch 'v3' into 3522-writerto-skipresponsebodyencodedecode
2 parents b235bef + 0a2f9a4 commit 0df0530

18 files changed

+214
-51
lines changed

.github/FUNDING.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# These are supported funding model platforms
22

33
patreon: goadesign
4-
github: raphael
4+
github: [raphael, tchssk]

.github/workflows/report-coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
ref: ${{ github.event.workflow_run.head_sha }}
1919

2020
- name: Download test coverage
21-
uses: dawidd6/action-download-artifact@v3
21+
uses: dawidd6/action-download-artifact@v6
2222
with:
2323
workflow: test.yml
2424
name: coverage

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,29 @@ promoting reuse and standardization across services.
7171
# Sponsors
7272

7373
<table width="100%">
74+
<tr>
75+
<td>
76+
<img width="1000" height="0" />
77+
<a href="https://zuplo.link/goa-web">
78+
<picture>
79+
<source media="(prefers-color-scheme: dark)" srcset="docs/zuplo-dark.png">
80+
<img src="docs/zuplo.png" alt="Zuplo" width="260" align="right">
81+
</picture>
82+
</a>
83+
<h3>Zuplo: Scale, Protect, and Productize your Goa API</h3>
84+
<p>
85+
Our API Gateway allows you to secure your API, scale it
86+
globally, generate documentation from your OpenAPI, and add
87+
monetization.
88+
</p>
89+
<a href="https://zuplo.link/goa-web">Start for Free</a>
90+
</td>
91+
</tr>
7492
<tr>
7593
<td>
7694
<img width="1000" height="0" />
7795
<a href="https://www.incident.io">
78-
<img src="https://incident.io/_next/static/media/logo-social-dark.6a523ace.png" alt="incident.io" width="260" align="right" />
96+
<img src="docs/incidentio.png" alt="incident.io" width="260" align="right" />
7997
</a>
8098
<h3>incident.io: Bounce back stronger after every incident</h3>
8199
<p>

codegen/cli/cli.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func BuildSubcommandData(svcName string, m *service.MethodData, buildFunction *B
178178
description = fmt.Sprintf("Make request to the %q endpoint", m.Name)
179179
}
180180

181-
if buildFunction == nil && len(flags) > 0 {
181+
if m.Payload != "" && buildFunction == nil && len(flags) > 0 {
182182
// No build function, just convert the arg to the body type
183183
var convPre, convSuff string
184184
target := "data"

docs/incidentio.png

28.6 KB
Loading

docs/zuplo-dark.png

147 KB
Loading

docs/zuplo.png

146 KB
Loading

dsl/attribute.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,8 @@ func Field(tag any, name string, args ...any) {
222222
// })
223223
func OneOf(name string, args ...any) {
224224
if len(args) > 2 {
225-
eval.ReportError("OneOf: wrong number of arguments")
225+
eval.TooManyArgError()
226+
return
226227
}
227228
fn, ok := args[len(args)-1].(func())
228229
if !ok {
@@ -315,7 +316,7 @@ func Example(args ...any) {
315316
var ok bool
316317
summary, ok = args[0].(string)
317318
if !ok {
318-
eval.InvalidArgError("summary (string)", summary)
319+
eval.InvalidArgError("summary (string)", args[0])
319320
return
320321
}
321322
arg = args[1]

dsl/http.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dsl
22

33
import (
4-
"fmt"
54
"strconv"
65
"strings"
76

@@ -146,7 +145,7 @@ const (
146145
// })
147146
func HTTP(fns ...func()) {
148147
if len(fns) > 1 {
149-
eval.InvalidArgError("zero or one function", fmt.Sprintf("%d functions", len(fns)))
148+
eval.TooManyArgError()
150149
return
151150
}
152151
fn := func() {}

dsl/response.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func parseResponseArgs(val any, args ...any) (code int, fn func()) {
247247
}
248248
case func():
249249
if len(args) > 0 {
250-
eval.InvalidArgError("int (HTTP status code)", val)
250+
eval.TooManyArgError()
251251
return
252252
}
253253
fn = t

dsl/user_type.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func Type(name string, args ...any) expr.UserType {
9494
base = &expr.Object{}
9595
fn = a
9696
if len(args) == 2 {
97-
eval.ReportError("only one argument allowed when it is a function")
97+
eval.TooManyArgError()
9898
return nil
9999
}
100100
default:

eval/eval.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,20 +240,26 @@ func finalizeSet(set ExpressionSet) {
240240

241241
// caller returns the name of calling function.
242242
func caller() string {
243-
for skip := 2; skip <= 4; skip++ {
243+
var latest string
244+
for skip := 2; skip <= 5; skip++ {
244245
pc, _, _, ok := runtime.Caller(skip)
245246
if !ok {
246247
break
247248
}
248249
name := runtime.FuncForPC(pc).Name()
249-
elems := strings.Split(name, ".")
250-
caller := elems[len(elems)-1]
250+
if !strings.HasPrefix(name, "goa.design/goa/v3/dsl.") {
251+
break
252+
}
253+
caller := strings.Split(strings.TrimPrefix(name, "goa.design/goa/v3/dsl."), ".")[0]
251254
for _, first := range caller {
252255
if unicode.IsUpper(first) {
253-
return caller
256+
latest = caller
254257
}
255258
break
256259
}
257260
}
261+
if latest != "" {
262+
return latest
263+
}
258264
return "<unknown>"
259265
}

eval/eval_test.go

Lines changed: 69 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,76 @@ import (
99
"goa.design/goa/v3/expr"
1010
)
1111

12-
func TestTooManyArgError(t *testing.T) {
13-
cases := map[string]struct {
14-
DSL func()
15-
Error string
12+
func TestInvalidArgError(t *testing.T) {
13+
dsls := map[string]struct {
14+
dsl func()
15+
want string
1616
}{
17-
"ArrayOf": {func() { ArrayOf(String, func() {}, func() {}) }, "too many arguments given to ArrayOf"},
18-
"Attribute": {func() { Type("name", func() { Attribute("name", 1, 2, 3, 4) }) }, "too many arguments given to Attribute"},
19-
"Example": {func() { Example(1, 2, 3) }, "too many arguments given to Example"},
20-
"Files": {func() { Files("path", "filename", func() {}, func() {}) }, "too many arguments given to Files"},
21-
"MapOf": {func() { MapOf(String, String, func() {}, func() {}) }, "too many arguments given to MapOf"},
22-
"MapParams": {func() { MapParams(1, 2) }, "too many arguments given to MapParams"},
23-
"Payload": {func() { Payload(String, 1, 2, 3) }, "too many arguments given to Payload"},
24-
"Response": {func() { API("name", func() { HTTP(func() { Response(StatusOK, "name", 1, 2) }) }) }, "too many arguments given to Response"},
25-
"Result": {func() { Result(String, 1, 2, 3) }, "too many arguments given to Result"},
26-
"ResultType": {func() { ResultType("identifier", "name", func() {}, func() {}) }, "too many arguments given to ResultType"},
27-
"Scope": {func() { BasicAuthSecurity("name", func() { Scope("name", "1", "2") }) }, "too many arguments given to Scope"},
28-
"Server": {func() { Server("name", func() {}, func() {}) }, "too many arguments given to Server"},
29-
"StreamingPayload": {func() { StreamingPayload(String, 1, 2, 3) }, "too many arguments given to StreamingPayload"},
30-
"StreamingResult": {func() { StreamingResult(String, 1, 2, 3) }, "too many arguments given to StreamingResult"},
31-
"Type": {func() { Type("name", 1, 2, 3) }, "too many arguments given to Type"},
17+
"Attribute": {func() { Type("name", func() { Attribute("name", String, "description", 1) }) }, "cannot use 1 (type int) as type func()"},
18+
"Body": {func() { Service("s", func() { Method("m", func() { HTTP(func() { Body(1) }) }) }) }, "cannot use 1 (type int) as type attribute name, user type or DSL"},
19+
"ErrorName (bool)": {func() { Type("name", func() { ErrorName(true) }) }, "cannot use true (type bool) as type name or position"},
20+
"ErrorName (int)": {func() { Type("name", func() { ErrorName(1, 2) }) }, "cannot use 2 (type int) as type name"},
21+
"Example": {func() { Example(1, 2) }, "cannot use 1 (type int) as type summary (string)"},
22+
"Headers": {func() { Headers(1) }, "cannot use 1 (type int) as type function"},
23+
"Param": {func() { API("name", func() { HTTP(func() { Params(1) }) }) }, "cannot use 1 (type int) as type function"},
24+
"Response": {func() { Service("s", func() { HTTP(func() { Response(1) }) }) }, "cannot use 1 (type int) as type name of error"},
25+
"ResultType": {func() { ResultType("identifier", 1) }, "cannot use 1 (type int) as type function or string"},
26+
"Security": {func() { Security(1) }, "cannot use 1 (type int) as type security scheme or security scheme name"},
27+
"Type": {func() { Type("name", 1) }, "cannot use 1 (type int) as type type or function"},
28+
}
29+
for name, tc := range dsls {
30+
t.Run(name, func(t *testing.T) {
31+
err := expr.RunInvalidDSL(t, tc.dsl)
32+
assert.Len(t, strings.Split(err.Error(), "\n"), 1)
33+
assert.Contains(t, err.Error(), tc.want)
34+
})
35+
}
36+
}
37+
38+
func TestTooManyArgError(t *testing.T) {
39+
dsls := map[string]func(){
40+
"APIKey": func() { Type("name", func() { APIKey("scheme", "name", 1, 2, 3) }) },
41+
"APIKeyField": func() { Type("name", func() { APIKeyField("tag", "scheme", "name", 1, 2, 3) }) },
42+
"AccessToken": func() { Type("name", func() { AccessToken("name", 1, 2, 3) }) },
43+
"AccessTokenField": func() { Type("name", func() { AccessTokenField("tag", "name", 1, 2, 3) }) },
44+
"ArrayOf": func() { ArrayOf(String, func() {}, func() {}) },
45+
"Attribute": func() { Type("name", func() { Attribute("name", 1, 2, 3, 4) }) },
46+
"Cookie": func() { API("name", func() { HTTP(func() { Cookie("name", 1, 2, 3, 4) }) }) },
47+
"Error": func() { API("name", func() { Error("name", 1, 2, 3, 4) }) },
48+
"ErrorName": func() { Type("name", func() { ErrorName("name", 1, 2, 3) }) },
49+
"Example": func() { Example(1, 2, 3) },
50+
"Field": func() { Type("name", func() { Field("tag", "name", 1, 2, 3, 4) }) },
51+
"Files": func() { Files("path", "filename", func() {}, func() {}) },
52+
"HTTP": func() { API("name", func() { HTTP(func() {}, func() {}) }) },
53+
"Header": func() { API("name", func() { HTTP(func() { Header("name", 1, 2, 3, 4) }) }) },
54+
"MapOf": func() { MapOf(String, String, func() {}, func() {}) },
55+
"MapParams": func() { MapParams(1, 2) },
56+
"OneOf": func() { OneOf("name", 1, 2, 3) },
57+
"Param": func() { API("name", func() { HTTP(func() { Param("name", 1, 2, 3, 4) }) }) },
58+
"Password": func() { Type("name", func() { Password("name", 1, 2, 3) }) },
59+
"PasswordField": func() { Type("name", func() { PasswordField("tag", "name", 1, 2, 3) }) },
60+
"Payload": func() { Payload(String, 1, 2, 3) },
61+
"Response (int)": func() { API("name", func() { HTTP(func() { Response(StatusOK, "name", 1, 2) }) }) },
62+
"Response (func)": func() { API("name", func() { HTTP(func() { Response("name", func() {}, func() {}) }) }) },
63+
"Result": func() { Result(String, 1, 2, 3) },
64+
"ResultType": func() { ResultType("identifier", "name", func() {}, func() {}) },
65+
"Scope": func() { BasicAuthSecurity("name", func() { Scope("name", "1", "2") }) },
66+
"Server": func() { Server("name", func() {}, func() {}) },
67+
"StreamingPayload": func() { StreamingPayload(String, 1, 2, 3) },
68+
"StreamingResult": func() { StreamingResult(String, 1, 2, 3) },
69+
"Token": func() { Type("name", func() { Token("name", 1, 2, 3) }) },
70+
"TokenField": func() { Type("name", func() { TokenField("tag", "name", 1, 2, 3) }) },
71+
"Type": func() { Type("name", 1, 2, 3) },
72+
"Type (func)": func() { Type("name", func() {}, func() {}) },
73+
"Username": func() { Type("name", func() { Username("name", 1, 2, 3) }) },
74+
"UsernameField": func() { Type("name", func() { UsernameField("tag", "name", 1, 2, 3) }) },
75+
"Variable": func() { API("a", func() { Server("s", func() { Host("h", func() { Variable("v", 1, 2, 3, 4) }) }) }) },
3276
}
33-
for _, tc := range cases {
34-
err := expr.RunInvalidDSL(t, tc.DSL)
35-
assert.Len(t, strings.Split(err.Error(), "\n"), 1)
36-
assert.Contains(t, err.Error(), tc.Error)
77+
for name, dsl := range dsls {
78+
t.Run(name, func(t *testing.T) {
79+
err := expr.RunInvalidDSL(t, dsl)
80+
assert.Len(t, strings.Split(err.Error(), "\n"), 1)
81+
assert.Contains(t, err.Error(), "too many arguments given to "+strings.Split(name, " ")[0])
82+
})
3783
}
3884
}

grpc/codegen/client_cli.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,6 @@ func ParseEndpoint(cc *grpc.ClientConn, opts ...grpc.CallOption) (goa.Endpoint,
222222
data, err = {{ $pkgName}}.{{ .BuildFunction.Name }}({{ range .BuildFunction.ActualParams }}*{{ . }}Flag, {{ end }})
223223
{{- else if .Conversion }}
224224
{{ .Conversion }}
225-
{{- else }}
226-
data = nil
227225
{{- end }}
228226
{{- end }}
229227
}

http/codegen/client_cli_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func TestClientCLIFiles(t *testing.T) {
2323
{"simple-parse", testdata.MultiSimpleDSL, testdata.MultiSimpleParseCode, 0, 3},
2424
{"multi-parse", testdata.MultiDSL, testdata.MultiParseCode, 0, 3},
2525
{"multi-required-payload", testdata.MultiRequiredPayloadDSL, testdata.MultiRequiredPayloadParseCode, 0, 3},
26+
{"skip-request-body-encode-decode", testdata.SkipRequestBodyEncodeDecodeDSL, testdata.SkipRequestBodyEncodeDecodeParseCode, 0, 3},
2627
{"streaming-parse", testdata.StreamingMultipleServicesDSL, testdata.StreamingParseCode, 0, 3},
2728
{"simple-build", testdata.MultiSimpleDSL, testdata.MultiSimpleBuildCode, 1, 1},
2829
{"multi-build", testdata.MultiDSL, testdata.MultiBuildCode, 1, 1},

http/codegen/templates/parse_endpoint.go.tpl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ func ParseEndpoint(
4141
data, err = {{ $pkgName}}.{{ .BuildFunction.Name }}({{ range .BuildFunction.ActualParams }}*{{ . }}Flag, {{ end }})
4242
{{- else if .Conversion }}
4343
{{ .Conversion }}
44-
{{- else }}
45-
data = nil
4644
{{- end }}
4745
{{- if .StreamFlag }}
4846
{{- if .BuildFunction }}

0 commit comments

Comments
 (0)