Skip to content

Commit

Permalink
Move templates out of Go code into their own files (#3456)
Browse files Browse the repository at this point in the history
* Move templates out of Go code into their own files

This makes the code clearer, avoids the ability to abuse templates (e.g. via string interpolation) and makes debugging template errors easier.

* Make readTemplates work on Windows

* Skip flaky tests (#3458)

Prevent random test failures during CI with the error message:

listen udp 127.0.0.1:62112: bind: An attempt was made to access a socket in a way forbidden by its access permissions.

Re-running tests fixes it but testing on Linux is enough anyway for these tests.

* No need to checkout to report test coverage (#3459)

* Use v3 branch for pushes, and feature branch for PRs when pushing code coverage (#3460)

* Use testify to simplify tests

* Move to testify

* Make tests work on Windows
  • Loading branch information
raphael committed Jan 23, 2024
1 parent 041a6d1 commit ff3c29d
Show file tree
Hide file tree
Showing 154 changed files with 3,533 additions and 3,992 deletions.
10 changes: 5 additions & 5 deletions codegen/example/example_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func exampleCLIMain(_ string, root *expr.RootExpr, svr *expr.ServerExpr) *codege
codegen.Header("", "main", specs),
{
Name: "cli-main-start",
Source: template("client_start"),
Source: readTemplate("client_start"),
Data: map[string]any{
"Server": svrdata,
},
Expand All @@ -53,7 +53,7 @@ func exampleCLIMain(_ string, root *expr.RootExpr, svr *expr.ServerExpr) *codege
},
}, {
Name: "cli-main-var-init",
Source: template("client_var_init"),
Source: readTemplate("client_var_init"),
Data: map[string]any{
"Server": svrdata,
},
Expand All @@ -62,7 +62,7 @@ func exampleCLIMain(_ string, root *expr.RootExpr, svr *expr.ServerExpr) *codege
},
}, {
Name: "cli-main-endpoint-init",
Source: template("client_endpoint_init"),
Source: readTemplate("client_endpoint_init"),
Data: map[string]any{
"Server": svrdata,
},
Expand All @@ -72,10 +72,10 @@ func exampleCLIMain(_ string, root *expr.RootExpr, svr *expr.ServerExpr) *codege
},
}, {
Name: "cli-main-end",
Source: template("client_end"),
Source: readTemplate("client_end"),
}, {
Name: "cli-main-usage",
Source: template("client_usage"),
Source: readTemplate("client_usage"),
Data: map[string]any{
"APIName": root.API.Name,
"Server": svrdata,
Expand Down
14 changes: 7 additions & 7 deletions codegen/example/example_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func exampleSvrMain(genpkg string, root *expr.RootExpr, svr *expr.ServerExpr) *c
codegen.Header("", "main", specs),
{
Name: "server-main-start",
Source: template("server_start"),
Source: readTemplate("server_start"),
Data: map[string]any{
"Server": svrdata,
},
Expand All @@ -87,13 +87,13 @@ func exampleSvrMain(genpkg string, root *expr.RootExpr, svr *expr.ServerExpr) *c
},
}, {
Name: "server-main-logger",
Source: template("server_logger"),
Source: readTemplate("server_logger"),
Data: map[string]any{
"APIPkg": apiPkg,
},
}, {
Name: "server-main-services",
Source: template("server_services"),
Source: readTemplate("server_services"),
Data: map[string]any{
"APIPkg": apiPkg,
"Services": svcData,
Expand All @@ -103,7 +103,7 @@ func exampleSvrMain(genpkg string, root *expr.RootExpr, svr *expr.ServerExpr) *c
},
}, {
Name: "server-main-endpoints",
Source: template("server_endpoints"),
Source: readTemplate("server_endpoints"),
Data: map[string]any{
"Services": svcData,
},
Expand All @@ -112,10 +112,10 @@ func exampleSvrMain(genpkg string, root *expr.RootExpr, svr *expr.ServerExpr) *c
},
}, {
Name: "server-main-interrupts",
Source: template("server_interrupts"),
Source: readTemplate("server_interrupts"),
}, {
Name: "server-main-handler",
Source: template("server_handler"),
Source: readTemplate("server_handler"),
Data: map[string]any{
"Server": svrdata,
"Services": svcData,
Expand All @@ -128,7 +128,7 @@ func exampleSvrMain(genpkg string, root *expr.RootExpr, svr *expr.ServerExpr) *c
},
{
Name: "server-main-end",
Source: template("server_end"),
Source: readTemplate("server_end"),
},
}

Expand Down
4 changes: 2 additions & 2 deletions codegen/example/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
//go:embed templates/*
var tmplFS embed.FS

// template returns the example template with the given name.
func template(name string) string {
// readTemplate returns the example template with the given name.
func readTemplate(name string) string {
content, err := tmplFS.ReadFile(path.Join("templates", name) + ".go.tpl")
if err != nil {
panic("failed to load template " + name + ": " + err.Error()) // Should never happen, bug if it does
Expand Down
61 changes: 3 additions & 58 deletions codegen/service/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,78 +30,23 @@ func ClientFile(_ string, service *expr.ServiceExpr) *codegen.File {
header := codegen.Header(service.Name+" client", svc.PkgName, imports)
def := &codegen.SectionTemplate{
Name: "client-struct",
Source: serviceClientT,
Source: readTemplate("service_client"),
Data: data,
}
init := &codegen.SectionTemplate{
Name: "client-init",
Source: serviceClientInitT,
Source: readTemplate("service_client_init"),
Data: data,
}
sections = []*codegen.SectionTemplate{header, def, init}
for _, m := range data.Methods {
sections = append(sections, &codegen.SectionTemplate{
Name: "client-method",
Source: serviceClientMethodT,
Source: readTemplate("service_client_method"),
Data: m,
})
}
}

return &codegen.File{Path: path, SectionTemplates: sections}
}

// input: endpointsData
const serviceClientT = `// {{ .ClientVarName }} is the {{ printf "%q" .Name }} service client.
type {{ .ClientVarName }} struct {
{{- range .Methods}}
{{ .VarName }}Endpoint goa.Endpoint
{{- end }}
}
`

// input: endpointsData
const serviceClientInitT = `{{ printf "New%s initializes a %q service client given the endpoints." .ClientVarName .Name | comment }}
func New{{ .ClientVarName }}({{ .ClientInitArgs }} goa.Endpoint) *{{ .ClientVarName }} {
return &{{ .ClientVarName }}{
{{- range .Methods }}
{{ .VarName }}Endpoint: {{ .ArgName }},
{{- end }}
}
}
`

// input: endpointsData
const serviceClientMethodT = `
{{ printf "%s calls the %q endpoint of the %q service." .VarName .Name .ServiceName | comment }}
{{- if .Errors }}
{{ printf "%s may return the following errors:" .VarName | comment }}
{{- range .Errors }}
// - {{ printf "%q" .ErrName}} (type {{ .TypeRef }}){{ if .Description }}: {{ .Description }}{{ end }}
{{- end }}
// - error: internal error
{{- end }}
{{- $resultType := .ResultRef }}
{{- if .ClientStream }}
{{- $resultType = .ClientStream.Interface }}
{{- end }}
func (c *{{ .ClientVarName }}) {{ .VarName }}(ctx context.Context{{ if .PayloadRef }}, p {{ .PayloadRef }}{{ end }}{{ if .MethodData.SkipRequestBodyEncodeDecode}}, req io.ReadCloser{{ end }}) ({{ if $resultType }}res {{ $resultType }}, {{ end }}{{ if .MethodData.SkipResponseBodyEncodeDecode }}resp io.ReadCloser, {{ end }}err error) {
{{- if or $resultType .MethodData.SkipResponseBodyEncodeDecode }}
var ires any
{{- end }}
{{ if or $resultType .MethodData.SkipResponseBodyEncodeDecode }}ires{{ else }}_{{ end }}, err = c.{{ .VarName}}Endpoint(ctx, {{ if .MethodData.SkipRequestBodyEncodeDecode }}&{{ .RequestStruct }}{ {{ if .PayloadRef }}Payload: p, {{ end }}Body: req }{{ else if .PayloadRef }}p{{ else }}nil{{ end }})
{{- if not (or $resultType .MethodData.SkipResponseBodyEncodeDecode) }}
return
{{- else }}
if err != nil {
return
}
{{- if .MethodData.SkipResponseBodyEncodeDecode }}
o := ires.(*{{ .MethodData.ResponseStruct }})
return {{ if .ResultRef }}o.Result, {{ end }}o.Body, nil
{{- else }}
return ires.({{ $resultType }}), nil
{{- end }}
{{- end }}
}
`
28 changes: 10 additions & 18 deletions codegen/service/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package service

import (
"bytes"
"fmt"
"go/format"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"goa.design/goa/v3/codegen"
"goa.design/goa/v3/codegen/service/testdata"
"goa.design/goa/v3/expr"
Expand Down Expand Up @@ -33,28 +36,17 @@ func TestClient(t *testing.T) {
for _, c := range cases {
t.Run(c.Name, func(t *testing.T) {
codegen.RunDSL(t, c.DSL)
if len(expr.Root.Services) != 1 {
t.Fatalf("got %d services, expected 1", len(expr.Root.Services))
}
require.Len(t, expr.Root.Services, 1)
fs := ClientFile("test/gen", expr.Root.Services[0])
if fs == nil {
t.Fatalf("got nil file, expected not nil")
}
require.NotNil(t, fs)
buf := new(bytes.Buffer)
for _, s := range fs.SectionTemplates[1:] {
if err := s.Write(buf); err != nil {
t.Fatal(err)
}
require.NoError(t, s.Write(buf))
}
bs, err := format.Source(buf.Bytes())
if err != nil {
fmt.Println(buf.String())
t.Fatal(err)
}
code := string(bs)
if code != c.Code {
t.Errorf("%s: got\n%s\ngot vs expected\n:%s", c.Name, code, codegen.Diff(t, code, c.Code))
}
require.NoError(t, err, buf.String())
code := strings.ReplaceAll(string(bs), "\r\n", "\n")
assert.Equal(t, c.Code, code)
})
}
}
30 changes: 3 additions & 27 deletions codegen/service/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ func ConvertFile(root *expr.RootExpr, service *expr.ServiceExpr) (*codegen.File,
}
sections = append(sections, &codegen.SectionTemplate{
Name: "convert-to",
Source: convertT,
Source: readTemplate("convert"),
Data: data,
})
}
Expand Down Expand Up @@ -298,7 +298,7 @@ func ConvertFile(root *expr.RootExpr, service *expr.ServiceExpr) (*codegen.File,
}
sections = append(sections, &codegen.SectionTemplate{
Name: "create-from",
Source: createT,
Source: readTemplate("create"),
Data: data,
})
}
Expand All @@ -312,7 +312,7 @@ func ConvertFile(root *expr.RootExpr, service *expr.ServiceExpr) (*codegen.File,
seen[tf.Name] = struct{}{}
sections = append(sections, &codegen.SectionTemplate{
Name: "convert-create-helper",
Source: transformHelperT,
Source: readTemplate("transform_helper"),
Data: tf,
})
}
Expand Down Expand Up @@ -743,27 +743,3 @@ func compatible(from expr.DataType, to reflect.Type, recs ...compRec) error {

return fmt.Errorf("types don't match: type of %s is %s but type of corresponding attribute is %s", rec.path, toName, from.Name())
}

// input: convertData
const convertT = `{{ printf "%s creates an instance of %s initialized from t." .Name .TypeName | comment }}
func (t {{ .ReceiverTypeRef }}) {{ .Name }}() {{ .TypeRef }} {
{{ .Code }}
return v
}
`

// input: convertData
const createT = `{{ printf "%s initializes t from the fields of v" .Name | comment }}
func (t {{ .ReceiverTypeRef }}) {{ .Name }}(v {{ .TypeRef }}) {
{{ .Code }}
*t = *temp
}
`

// input: TransformFunctionData
const transformHelperT = `{{ printf "%s builds a value of type %s from a value of type %s." .Name .ResultTypeRef .ParamTypeRef | comment }}
func {{ .Name }}(v {{ .ParamTypeRef }}) {{ .ResultTypeRef }} {
{{ .Code }}
return res
}
`

0 comments on commit ff3c29d

Please sign in to comment.