Skip to content

Commit

Permalink
feat: introduce types.ftl.go to register sumtypes, which fixes enco…
Browse files Browse the repository at this point in the history
…ding in unit tests (#1909)

Fixes #1577

This change introduces a new generated file `types.ftl.go` in the
user-defined package itself to make sure sumtype registrations get
called when running unit tests.

Notes:
* This change also includes a subpackage `subpackage` in the test data
that is not yet unit tested. Unit tests should be added (identical to
the parent package's unit tests) after
#1903 is resolved. Some work
will also need to be done to extend the `types.ftl.go` generation to
working on subpackages.
* This works by extending the existing logic operating on
`mainModuleContext`, which means that code now generates not only just
the literal `main` package, but also the conceptual _main_ package's
additional artifacts. I couldn't come up with a name that would be
better, so it's left as-is in this PR, but please let me know if you
think of something better.
  • Loading branch information
deniseli authored Jul 2, 2024
1 parent 8425df0 commit 15a6ebf
Show file tree
Hide file tree
Showing 22 changed files with 613 additions and 15 deletions.
3 changes: 3 additions & 0 deletions backend/schema/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ func EncodeComments(comments []string) string {

w := &strings.Builder{}
for _, c := range comments {
if c == "Code generated by FTL. DO NOT EDIT." {
continue
}
space := ""
// Empty lines should not have a trailing space.
if c != "" {
Expand Down
3 changes: 3 additions & 0 deletions buildengine/testdata/alpha/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions buildengine/testdata/another/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions buildengine/testdata/other/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 22 additions & 3 deletions common/moduleconfig/moduleconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func replacementWatches(moduleDir, deployDir string) ([]string, error) {

// findReplacedImports finds Go files with imports that are specified in the replacements.
func findReplacedImports(moduleDir, deployDir string, replacements map[string]string) ([]string, error) {
var libPaths []string
libPaths := make(map[string]bool)

err := filepath.WalkDir(moduleDir, func(path string, d os.DirEntry, err error) error {
if err != nil {
Expand All @@ -243,7 +243,7 @@ func findReplacedImports(moduleDir, deployDir string, replacements map[string]st
for oldPath, newPath := range replacements {
if strings.HasPrefix(imp, oldPath) {
resolvedPath := filepath.Join(newPath, strings.TrimPrefix(imp, oldPath))
libPaths = append(libPaths, resolvedPath)
libPaths[resolvedPath] = true
break // Only add the library path once for each import match
}
}
Expand All @@ -252,7 +252,26 @@ func findReplacedImports(moduleDir, deployDir string, replacements map[string]st
return nil
})

return libPaths, err
return deduplicateLibPaths(libPaths), err
}

func deduplicateLibPaths(libPaths map[string]bool) []string {
for maybeParentPath := range libPaths {
for path := range libPaths {
if maybeParentPath != path && strings.HasPrefix(path, maybeParentPath) {
libPaths[path] = false
}
}
}

paths := []string{}
for path, shouldReturn := range libPaths {
if shouldReturn {
paths = append(paths, path)
}
}

return paths
}

func parseImports(filePath string) ([]string, error) {
Expand Down
17 changes: 17 additions & 0 deletions go-runtime/compile/build-template/types.ftl.go.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Code generated by FTL. DO NOT EDIT.
package {{.Name}}
{{if .LocalSumTypes }}
import "github.com/TBD54566975/ftl/go-runtime/ftl/reflection"

func init() {
reflection.Register(
{{- range .LocalSumTypes}}
reflection.SumType[{{.Discriminator}}](
{{- range .Variants}}
*new({{.Name}}),
{{- end}}
),
{{- end}}
)
}
{{- end}}
49 changes: 37 additions & 12 deletions go-runtime/compile/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ type goVerb struct {
}

type mainModuleContext struct {
GoVersion string
FTLVersion string
Name string
Verbs []goVerb
Replacements []*modfile.Replace
SumTypes []goSumType
GoVersion string
FTLVersion string
Name string
Verbs []goVerb
Replacements []*modfile.Replace
SumTypes []goSumType
LocalSumTypes []goSumType
}

type goSumType struct {
Expand Down Expand Up @@ -185,12 +186,13 @@ func Build(ctx context.Context, moduleDir string, sch *schema.Schema, filesTrans
goVerbs = append(goVerbs, goverb)
}
if err := internal.ScaffoldZip(buildTemplateFiles(), moduleDir, mainModuleContext{
GoVersion: goModVersion,
FTLVersion: ftlVersion,
Name: result.Module.Name,
Verbs: goVerbs,
Replacements: replacements,
SumTypes: getSumTypes(result.Module, sch, result.NativeNames),
GoVersion: goModVersion,
FTLVersion: ftlVersion,
Name: result.Module.Name,
Verbs: goVerbs,
Replacements: replacements,
SumTypes: getSumTypes(result.Module, sch, result.NativeNames),
LocalSumTypes: getLocalSumTypes(result.Module),
}, scaffolder.Exclude("^go.mod$"), scaffolder.Functions(funcs)); err != nil {
return err
}
Expand Down Expand Up @@ -553,6 +555,29 @@ func writeSchemaErrors(config moduleconfig.ModuleConfig, errors []*schema.Error)
return os.WriteFile(config.Abs().Errors, elBytes, 0600)
}

func getLocalSumTypes(module *schema.Module) []goSumType {
sumTypes := make(map[string]goSumType)
for _, d := range module.Decls {
if e, ok := d.(*schema.Enum); ok && !e.IsValueEnum() {
variants := make([]goSumTypeVariant, 0, len(e.Variants))
for _, v := range e.Variants {
variants = append(variants, goSumTypeVariant{ //nolint:forcetypeassert
Name: v.Name,
})
}
sumTypes[e.Name] = goSumType{
Discriminator: e.Name,
Variants: variants,
}
}
}
out := gomaps.Values(sumTypes)
slices.SortFunc(out, func(a, b goSumType) int {
return strings.Compare(a.Discriminator, b.Discriminator)
})
return out
}

func getSumTypes(module *schema.Module, sch *schema.Schema, nativeNames NativeNames) []goSumType {
sumTypes := make(map[string]goSumType)
for _, d := range module.Decls {
Expand Down
3 changes: 3 additions & 0 deletions go-runtime/compile/testdata/named/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions go-runtime/compile/testdata/namedext/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions go-runtime/compile/testdata/one/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions go-runtime/compile/testdata/parent/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions go-runtime/compile/testdata/pubsub/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions go-runtime/compile/testdata/subscriber/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions go-runtime/compile/testdata/two/types.ftl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions go-runtime/ftl/ftl_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,11 @@ func TestSchemaGenerate(t *testing.T) {
in.FileContains("build/schema-generate/test.txt", "olleh"),
)
}

func TestTypeRegistryUnitTest(t *testing.T) {
in.Run(t, "",
in.CopyModule("typeregistry"),
in.Deploy("typeregistry"),
in.ExecModuleTest("typeregistry"),
)
}
2 changes: 2 additions & 0 deletions go-runtime/ftl/testdata/go/typeregistry/ftl.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module = "typeregistry"
language = "go"
62 changes: 62 additions & 0 deletions go-runtime/ftl/testdata/go/typeregistry/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
module ftl/typeregistry

go 1.22.2

toolchain go1.22.4

require (
github.com/TBD54566975/ftl v1.1.5
github.com/alecthomas/assert/v2 v2.10.0
)

require (
connectrpc.com/connect v1.16.1 // indirect
connectrpc.com/grpcreflect v1.2.0 // indirect
connectrpc.com/otelconnect v0.7.0 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/TBD54566975/scaffolder v1.0.0 // indirect
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
github.com/alecthomas/concurrency v0.0.2 // indirect
github.com/alecthomas/participle/v2 v2.1.1 // indirect
github.com/alecthomas/repr v0.4.0 // indirect
github.com/alecthomas/types v0.16.0 // indirect
github.com/alessio/shellescape v1.4.2 // indirect
github.com/aws/aws-sdk-go-v2 v1.30.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 // indirect
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.1 // indirect
github.com/aws/smithy-go v1.20.3 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/danieljoos/wincred v1.2.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/puzpuzpuz/xsync/v3 v3.2.0 // indirect
github.com/swaggest/jsonschema-go v0.3.72 // indirect
github.com/swaggest/refl v1.3.0 // indirect
github.com/zalando/go-keyring v0.2.5 // indirect
go.opentelemetry.io/otel v1.27.0 // indirect
go.opentelemetry.io/otel/metric v1.27.0 // indirect
go.opentelemetry.io/otel/trace v1.27.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)

replace github.com/TBD54566975/ftl => ../../../../..
Loading

0 comments on commit 15a6ebf

Please sign in to comment.