Skip to content

Commit

Permalink
chore: statically extract .proto from Go source (#2973)
Browse files Browse the repository at this point in the history
This adds a general purpose command `go2proto` that statically generates
a `.proto` file from Go source code. This used to be done via
reflection, but that resulted in a chicken and egg problem whereby the
reflection code needed to be compilable in order to generate the
protobuf files that the reflection code depended on.

A couple of minor side-effects:

1. This will automatically extract sum types and enums.
2. The runtime types have been moved directly into the schema, as
opposed to only existing in the proto.
3. Sum type elements will need to be tagged with a `//protobuf:<id>`
directive.

These are the breaking changes:

```
backend/protos/xyz/block/ftl/v1/schema/schema.proto:43:26:Field "5" on message "Data" changed name from "typeParameters" to "type_parameters".
backend/protos/xyz/block/ftl/v1/schema/schema.proto:162:3:Field "2" with name "kind" on message "MetadataAlias" changed type from "int64" to "enum".
backend/protos/xyz/block/ftl/v1/schema/schema.proto:197:10:Field "3" on message "MetadataRetry" changed name from "minBackoff" to "min_backoff".
backend/protos/xyz/block/ftl/v1/schema/schema.proto:198:10:Field "4" on message "MetadataRetry" changed name from "maxBackoff" to "max_backoff".
backend/protos/xyz/block/ftl/v1/schema/schema.proto:210:10:Field "3" on message "MetadataTypeMap" changed name from "nativeName" to "native_name".
backend/protos/xyz/block/ftl/v1/schema/schema.proto:245:17:Field "4" on message "Ref" changed name from "typeParameters" to "type_parameters".
backend/protos/xyz/block/ftl/v1/schema/schema.proto:350:3:Field "3" with name "status" on message "VerbRuntime" changed type from "xyz.block.ftl.v1.schema.Status" to "xyz.block.ftl.v1.schema.VerbStatus".
```

None of these changes should effect wire compatibility.

Fixes #2935
  • Loading branch information
alecthomas authored Oct 3, 2024
1 parent e844771 commit 0a7e36b
Show file tree
Hide file tree
Showing 59 changed files with 2,108 additions and 1,692 deletions.
2 changes: 1 addition & 1 deletion .go-arch-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ components:
frontend: { in: frontend/console/** }
ftl-gen-lsp-cmd: { in: cmd/ftl-gen-lsp/** }
ftl-initdb-cmd: { in: cmd/ftl-initdb/** }
ftl-schema-cmd: { in: cmd/ftl-schema/** }
go2proto: { in: cmd/go2proto/** }
lint-commit-or-rollback-cmd: { in: cmd/lint-commit-or-rollback/** }
databasetesting: { in: backend/controller/sql/databasetesting/** }
sql: { in: backend/controller/sql/** }
Expand Down
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ linters-settings:
# ignorePackageGlobs:
# - github.com/TBD54566975/ftl/*
spancheck:

extra-start-span-signatures:
- "github.com/TBD54566975/ftl/backend/controller/observability.BeginSpan:opentelemetry"
issues:
Expand Down Expand Up @@ -143,3 +142,4 @@ issues:
- "strings.Title has been deprecated"
- "error returned from external package is unwrapped.*TranslatePGError"
- "struct literal uses unkeyed fields"
- "exported: comment on exported type"
4 changes: 2 additions & 2 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ pnpm-install:

# Regenerate protos
build-protos: pnpm-install
@mk {{SCHEMA_OUT}} : internal/schema -- "ftl-schema > {{SCHEMA_OUT}} && buf format -w && buf lint"
@mk {{SCHEMA_OUT}} : internal/schema -- "go2proto -o "{{SCHEMA_OUT}}" -g 'github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/schema;schemapb' xyz.block.ftl.v1.schema ./internal/schema.Schema && buf format -w && buf lint"
@mk {{PROTOS_OUT}} : {{PROTOS_IN}} -- "cd backend/protos && buf generate"

# Unconditionally rebuild protos
build-protos-unconditionally: pnpm-install
ftl-schema > {{SCHEMA_OUT}} && buf format -w && buf lint
go2proto -o "{{SCHEMA_OUT}}" -g 'github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/schema;schemapb' xyz.block.ftl.v1.schema ./internal/schema.Schema && buf format -w && buf lint
cd backend/protos && buf generate

# Run integration test(s)
Expand Down
4 changes: 2 additions & 2 deletions backend/controller/ingress/ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func TestValidation(t *testing.T) {
{name: "IntAlias",
schema: `module test {
typealias IntAlias Int
data Test { intValue test.IntAlias }
data Test { intValue test.IntAlias }
}`,
request: obj{"intValue": 10.0},
},
Expand Down Expand Up @@ -245,7 +245,7 @@ func TestResponseBodyForVerb(t *testing.T) {
&schema.Data{
Name: "Test",
Fields: []*schema.Field{
{Name: "message", Type: &schema.String{}, Metadata: []schema.Metadata{&schema.MetadataAlias{Kind: schema.AliasKindJSON, Alias: "msg"}}},
{Name: "message", Type: &schema.String{}, Metadata: []schema.Metadata{&schema.MetadataAlias{Kind: schema.AliasKindJson, Alias: "msg"}}},
},
},
jsonVerb,
Expand Down
2 changes: 1 addition & 1 deletion backend/controller/ingress/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ func parseQueryParams(values url.Values, data *schema.Data) (map[string]any, err

var field *schema.Field
for _, f := range data.Fields {
if jsonAlias, ok := f.Alias(schema.AliasKindJSON).Get(); (ok && jsonAlias == key) || f.Name == key {
if jsonAlias, ok := f.Alias(schema.AliasKindJson).Get(); (ok && jsonAlias == key) || f.Name == key {
field = f
}
for _, typeParam := range data.TypeParameters {
Expand Down
2 changes: 1 addition & 1 deletion backend/controller/ingress/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func bodyForType(typ schema.Type, sch *schema.Schema, data []byte) ([]byte, erro
}

err = schema.TransformAliasedFields(sch, t, response, func(obj map[string]any, field *schema.Field) string {
if jsonAlias, ok := field.Alias(schema.AliasKindJSON).Get(); ok && field.Name != jsonAlias {
if jsonAlias, ok := field.Alias(schema.AliasKindJson).Get(); ok && field.Name != jsonAlias {
obj[jsonAlias] = obj[field.Name]
delete(obj, field.Name)
return jsonAlias
Expand Down
Loading

0 comments on commit 0a7e36b

Please sign in to comment.