Skip to content

Commit

Permalink
fix: go modules can build even if queries file is missing (#4216)
Browse files Browse the repository at this point in the history
fixes #4129

Builds would fail in this chicken and egg sitatuation:
- Queries file did not exist (or was behind)
- Verbs referred to types or clients that should eventually be in the
queries file

Extracting schema results in an error that the parameters to a verb does
not follow the pattern `ctx, req?, resources...` because the sql verb
client doesn't exist and so is not recognized as a resource.

Solution:
- Extract schema from the module as usual
- Rather than immediately exiting if there was a terminal error, we
continue to scaffold as usual
- We then check for terminal errors from schema extraction
    - If there was some and scaffolding did happen, re-extract schema
  • Loading branch information
matt2e authored Jan 29, 2025
1 parent 4ae7c59 commit bf9fb8c
Show file tree
Hide file tree
Showing 10 changed files with 511 additions and 6 deletions.
22 changes: 16 additions & 6 deletions go-runtime/compile/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,12 +529,8 @@ func Build(ctx context.Context, projectConfig projectconfig.Config, stubsRoot st
if err != nil {
return moduleSch, nil, fmt.Errorf("could not extract schema: %w", err)
}
if builderrors.ContainsTerminalError(extractResult.Errors) {
// Only bail if schema errors contain elements at level ERROR.
// If errors are only at levels below ERROR (e.g. INFO, WARN), the schema can still be used.
return moduleSch, extractResult.Errors, nil
}

// We do not fail yet if result has terminal errors. These errors may be due to missing templated files (queries.ftl.go).
// Instead we scaffold if needed and then re-extract the schema to see if the errors are resolved.
logger.Debugf("Generating main package")
projectName := projectConfig.Name
mctx, err := buildMainDeploymentContext(sch, extractResult, goModVersion, projectName, sharedModulesPaths, replacements)
Expand All @@ -546,6 +542,20 @@ func Build(ctx context.Context, projectConfig projectconfig.Config, stubsRoot st
return moduleSch, nil, err // nolint:wrapcheck
}

if mainModuleCtxChanged && builderrors.ContainsTerminalError(extractResult.Errors) {
// We may have terminal errors that are resolved by scaffolding queries.
logger.Debugf("Re-extracting schema after scaffolding")
extractResult, err = extract.Extract(config.Dir, sch)
if err != nil {
return moduleSch, nil, fmt.Errorf("could not extract schema: %w", err)
}
}
if builderrors.ContainsTerminalError(extractResult.Errors) {
// Only bail if schema errors contain elements at level ERROR.
// If errors are only at levels below ERROR (e.g. INFO, WARN), the schema can still be used.
return moduleSch, extractResult.Errors, nil
}

logger.Debugf("Writing launch script")
if err := writeLaunchScript(buildDir); err != nil {
return moduleSch, nil, err
Expand Down
15 changes: 15 additions & 0 deletions go-runtime/compile/compile_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
package compile_test

import (
"os"
"path/filepath"
"testing"
"time"

Expand Down Expand Up @@ -61,3 +63,16 @@ func TestNonStructRequestResponse(t *testing.T) {
}),
)
}

// TestBuildWithoutQueries ensures that the build command does not fail when queries.ftl.go is missing.
func TestBuildWithoutQueries(t *testing.T) {
in.Run(t,
in.CopyModule("missingqueries"),
func(t testing.TB, ic in.TestContext) {
assert.NoError(t, os.Remove(filepath.Join(ic.WorkingDir(), "missingqueries/queries.ftl.go")))
},
in.Fail(in.FileExists("missingqueries/queries.ftl.go"), "queries.ftl.go should not exist yet"),
in.Deploy("missingqueries"),
in.FileExists("missingqueries/queries.ftl.go"),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

-- name: InsertPrice :exec
INSERT INTO prices (code, price, time, currency) VALUES (?, ?, ?, ?);
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- migrate:up
CREATE TABLE prices (
code VARCHAR(255) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
time TIMESTAMP NOT NULL,
currency VARCHAR(3) NOT NULL
);

-- migrate:down
DROP TABLE prices;
2 changes: 2 additions & 0 deletions go-runtime/compile/testdata/go/missingqueries/ftl.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module = "missingqueries"
language = "go"
70 changes: 70 additions & 0 deletions go-runtime/compile/testdata/go/missingqueries/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
module ftl/missingqueries

go 1.23.4

require (
github.com/alecthomas/types v0.17.0
github.com/block/ftl v0.433.2
)

require (
al.essio.dev/pkg/shellescape v1.5.1 // indirect
connectrpc.com/connect v1.16.2 // indirect
connectrpc.com/grpcreflect v1.3.0 // indirect
connectrpc.com/otelconnect v0.7.1 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/XSAM/otelsql v0.36.0 // indirect
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
github.com/alecthomas/concurrency v0.0.2 // indirect
github.com/alecthomas/kong v1.6.1 // indirect
github.com/alecthomas/participle/v2 v2.1.1 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/danieljoos/wincred v1.2.2 // indirect
github.com/deckarep/golang-set/v2 v2.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/hashicorp/cronexpr v1.1.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.2 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/lib/pq v1.10.9 // 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.4.1 // indirect
github.com/swaggest/jsonschema-go v0.3.73 // indirect
github.com/swaggest/refl v1.3.0 // indirect
github.com/zalando/go-keyring v0.2.6 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.34.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.34.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect
go.opentelemetry.io/otel/metric v1.34.0 // indirect
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
google.golang.org/grpc v1.69.4 // indirect
google.golang.org/protobuf v1.36.3 // indirect
)

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

0 comments on commit bf9fb8c

Please sign in to comment.