Skip to content

Commit

Permalink
fix: generated external modules don't import from metadata refs (#1110)
Browse files Browse the repository at this point in the history
when we generate an external module, we stub the verb bodies. we
shouldn't add imports which are only dependencies of the verb expression
body because this import may be unused once the body is stubbed, causing
build errors.
  • Loading branch information
worstell authored Mar 19, 2024
1 parent 9245419 commit a07113e
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 2 deletions.
16 changes: 16 additions & 0 deletions backend/schema/visit.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,19 @@ func Visit(n Node, visit func(n Node, next func() error) error) error {
return nil
})
}

// VisitExcludingMetadataChildren visits all nodes in the schema except the children of metadata nodes.
// This is used when generating external modules to avoid adding imports only referenced in the bodies of
// stubbed verbs.
func VisitExcludingMetadataChildren(n Node, visit func(n Node, next func() error) error) error {
return visit(n, func() error {
if _, ok := n.(Metadata); !ok {
for _, child := range n.schemaChildren() {
if err := VisitExcludingMetadataChildren(child, visit); err != nil {
return err
}
}
}
return nil
})
}
50 changes: 50 additions & 0 deletions buildengine/build_go_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,53 @@ func Nothing(context.Context) error {
assertGeneratedModule("go/modules/other/external_module.go", expected),
})
}

func TestMetadataImportsExcluded(t *testing.T) {
sch := &schema.Schema{
Modules: []*schema.Module{
schema.Builtins(),
{Name: "test", Decls: []schema.Decl{
&schema.Data{Name: "Req"},
&schema.Data{Name: "Resp"},
&schema.Verb{
Name: "call",
Request: &schema.Ref{Name: "Req"},
Response: &schema.Ref{Name: "Resp"},
Metadata: []schema.Metadata{
&schema.MetadataCalls{Calls: []*schema.Ref{{Name: "verb", Module: "other"}}},
},
},
}},
},
}
expected := `// Code generated by FTL. DO NOT EDIT.
//ftl:module test
package test
import (
"context"
)
var _ = context.Background
type Req struct {
}
type Resp struct {
}
//ftl:verb
func Call(context.Context, Req) (Resp, error) {
panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.Call()")
}
`
bctx := buildContext{
moduleDir: "testdata/modules/another",
buildDir: "_ftl",
sch: sch,
}
testBuild(t, bctx, []assertion{
assertGeneratedModule("go/modules/test/external_module.go", expected),
})
}
2 changes: 1 addition & 1 deletion buildengine/build_kotlin.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ var scaffoldFuncs = scaffolder.FuncMap{
},
"imports": func(m *schema.Module) []string {
imports := sets.NewSet[string]()
_ = schema.Visit(m, func(n schema.Node, next func() error) error {
_ = schema.VisitExcludingMetadataChildren(m, func(n schema.Node, next func() error) error {
switch n.(type) {
case *schema.Verb:
imports.Append("xyz.block.ftl.Context", "xyz.block.ftl.Ignore", "xyz.block.ftl.Verb")
Expand Down
2 changes: 1 addition & 1 deletion go-runtime/compile/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ var scaffoldFuncs = scaffolder.FuncMap{
},
"imports": func(m *schema.Module) map[string]string {
imports := map[string]string{}
_ = schema.Visit(m, func(n schema.Node, next func() error) error {
_ = schema.VisitExcludingMetadataChildren(m, func(n schema.Node, next func() error) error {
switch n := n.(type) {
case *schema.Ref:
if n.Module == "" || n.Module == m.Name {
Expand Down

0 comments on commit a07113e

Please sign in to comment.