Skip to content

Commit

Permalink
feat: add local schema diff
Browse files Browse the repository at this point in the history
If no remote URI is specified for schema diff it will attempt to diff the local project

closes #2174
  • Loading branch information
stuartwdouglas committed Jul 26, 2024
1 parent 26e7d83 commit 0ca3b26
Showing 1 changed file with 69 additions and 3 deletions.
72 changes: 69 additions & 3 deletions cmd/ftl/cmd_schema_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package main

import (
"context"
"errors"
"fmt"
"github.com/TBD54566975/ftl/common/projectconfig"
"google.golang.org/protobuf/proto"
"net/url"
"os"
"path/filepath"

"connectrpc.com/connect"
"github.com/hexops/gotextdiff"
Expand All @@ -22,12 +26,19 @@ import (
)

type schemaDiffCmd struct {
OtherEndpoint url.URL `arg:"" help:"Other endpoint URL to compare against."`
OtherEndpoint url.URL `arg:"" help:"Other endpoint URL to compare against. If this is not specified then ftl will perform a diff against the local schema." optional:""`
Color bool `help:"Enable colored output regardless of TTY."`
}

func (d *schemaDiffCmd) Run(ctx context.Context, currentURL *url.URL) error {
other, err := schemaForURL(ctx, d.OtherEndpoint)
func (d *schemaDiffCmd) Run(ctx context.Context, currentURL *url.URL, projConfig projectconfig.Config) error {
var other *schema.Schema
var err error
if d.OtherEndpoint.String() == "" {
other, err = localSchema(ctx, projConfig)
} else {
other, err = schemaForURL(ctx, d.OtherEndpoint)
}

if err != nil {
return fmt.Errorf("failed to get other schema: %w", err)
}
Expand Down Expand Up @@ -57,6 +68,61 @@ func (d *schemaDiffCmd) Run(ctx context.Context, currentURL *url.URL) error {
return nil
}

func localSchema(ctx context.Context, moduleDirs projectconfig.Config) (*schema.Schema, error) {
pb := &schemapb.Schema{}
found := false
tried := ""
moduleFound := false
moduleTried := ""
for _, modulePaths := range moduleDirs.AbsModuleDirs() {
entries, err := os.ReadDir(modulePaths)
if err != nil {
return nil, fmt.Errorf("failed to list directory %w", err)
}
for _, module := range entries {
if !module.IsDir() {
continue
}
path := filepath.Join(modulePaths, module.Name(), ".ftl", "schema.pb")
mod, err := loadProtoSchema(path)
if err != nil {
moduleTried += fmt.Sprintf("failed to read schema file %s; did you run ftl build?", path)
} else {
println(path)
moduleFound = true
found = true
pb.Modules = append(pb.Modules, mod)
}
}
}
if !moduleFound {
tried += moduleTried
}

if !found {
return nil, errors.New(tried)
}

s, err := schema.FromProto(pb)
if err != nil {
return nil, fmt.Errorf("failed to parse local schema: %w", err)
}
return s, nil
}

func loadProtoSchema(file string) (*schemapb.Module, error) {
content, err := os.ReadFile(file)
if err != nil {
return nil, err
}
module := &schemapb.Module{}
err = proto.Unmarshal(content, module)
if err != nil {
return nil, err
}
return module, nil
}

func schemaForURL(ctx context.Context, url url.URL) (*schema.Schema, error) {
client := rpc.Dial(ftlv1connect.NewControllerServiceClient, url.String(), log.Error)
resp, err := client.PullSchema(ctx, connect.NewRequest(&ftlv1.PullSchemaRequest{}))
Expand Down

0 comments on commit 0ca3b26

Please sign in to comment.