Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Support multiple clients in the same package #5

Merged
merged 2 commits into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ module github.com/cloudquery/codegen
go 1.19

require (
github.com/cloudquery/plugin-sdk v1.24.0
github.com/google/go-cmp v0.5.9
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30
)

require golang.org/x/text v0.5.0 // indirect
10 changes: 2 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
github.com/cloudquery/plugin-sdk v1.24.0 h1:vgi3RImpSlnhacg/zbrpsbUEsYpG51UB5KVkNhpX1cs=
github.com/cloudquery/plugin-sdk v1.24.0/go.mod h1:teMPyCON3uPdMsHvzpSiOg+IK2sOR5Tf9dYLreoURzI=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 h1:m9O6OTJ627iFnN2JIWfdqlZCzneRO6EEBsHXI25P8ws=
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
58 changes: 46 additions & 12 deletions interfaces/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"strings"
"text/template"

"github.com/cloudquery/plugin-sdk/caser"
"golang.org/x/exp/maps"
)

//go:embed templates/*.go.tpl
Expand Down Expand Up @@ -51,6 +51,31 @@ func WithExtraImports(f func(reflect.Method) []string) Option {
}
}

func getTemplateDataFromClientInfos(clientInfos []clientInfo) []serviceTemplateData {
services := make([]serviceTemplateData, 0)
serviceMap := make(map[string][]clientInfo)
for _, clientInfo := range clientInfos {
serviceMap[clientInfo.PackageName] = append(serviceMap[clientInfo.PackageName], clientInfo)
}
for packageName, clientInfos := range serviceMap {
imports := make(map[string]bool)
clientsTemplateData := make([]clientTemplateData, 0)
for _, clientInfo := range clientInfos {
imports[clientInfo.Import] = true
for _, extraImport := range clientInfo.ExtraImports {
imports[extraImport] = true
}
clientsTemplateData = append(clientsTemplateData, clientTemplateData{Name: clientInfo.ClientName, Signatures: clientInfo.Signatures})
}
services = append(services, serviceTemplateData{
PackageName: packageName,
Imports: maps.Keys(imports),
Clients: clientsTemplateData,
})
}
return services
}

// Generate generates service interfaces to be used for generating
// mocks. The clients passed in as the first argument should be structs that will be used to
// generate the service interfaces. The second argument, dir, is the path to the output
Expand All @@ -62,9 +87,9 @@ func Generate(clients []any, dir string, opts ...Option) error {
}
options.SetDefaults()

services := make([]serviceInfo, 0)
clientInfos := make([]clientInfo, 0)
for _, client := range clients {
services = append(services, getServiceInfo(client, options))
clientInfos = append(clientInfos, getClientInfo(client, options))
}

// write individual service files
Expand All @@ -73,6 +98,8 @@ func Generate(clients []any, dir string, opts ...Option) error {
return err
}

services := getTemplateDataFromClientInfos(clientInfos)

for _, service := range services {
buff := bytes.Buffer{}
if err := serviceTpl.Execute(&buff, service); err != nil {
Expand All @@ -81,7 +108,7 @@ func Generate(clients []any, dir string, opts ...Option) error {
filePath := path.Join(dir, fmt.Sprintf("%s.go", service.PackageName))
err := formatAndWriteFile(filePath, buff)
if err != nil {
return fmt.Errorf("failed to format and write file for service %v: %w", service.Name, err)
return fmt.Errorf("failed to format and write file for service %v: %w", service, err)
}
}

Expand Down Expand Up @@ -141,24 +168,32 @@ func signature(name string, f any) string {
return buf.String()
}

type serviceInfo struct {
type clientInfo struct {
Import string
Name string
PackageName string
ClientName string
Signatures []string
ExtraImports []string
}

func getServiceInfo(client any, opts *Options) serviceInfo {
type clientTemplateData struct {
Name string
Signatures []string
}

type serviceTemplateData struct {
PackageName string
Imports []string
Clients []clientTemplateData
}

func getClientInfo(client any, opts *Options) clientInfo {
v := reflect.ValueOf(client)
t := v.Type()
pkgPath := t.Elem().PkgPath()
parts := strings.Split(pkgPath, "/")
pkgName := parts[len(parts)-1]
csr := caser.New()
name := csr.ToPascal(pkgName)
clientName := name + "Client"
clientName := t.Elem().Name()
signatures := make([]string, 0)
extraImports := make([]string, 0)
for i := 0; i < t.NumMethod(); i++ {
Expand All @@ -169,9 +204,8 @@ func getServiceInfo(client any, opts *Options) serviceInfo {
}
extraImports = append(extraImports, opts.ExtraImports(method)...)
}
return serviceInfo{
return clientInfo{
Import: pkgPath,
Name: name,
PackageName: pkgName,
ClientName: clientName,
Signatures: signatures,
Expand Down
55 changes: 53 additions & 2 deletions interfaces/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,39 @@ import (
"net/http"
)

//go:generate mockgen -package=mocks -destination=../mocks/interfaces.go -source=interfaces.go InterfacesClient
type InterfacesClient interface {
//go:generate mockgen -package=mocks -destination=../mocks/interfaces.go -source=interfaces.go Client
type Client interface {
ListTables(context.Context) error
NewPager(context.Context) *interfaces.Pager[interfaces.Response]
}
`

type Client2 struct{}

func (*Client2) ListTables(_ context.Context) error {
return nil
}

var wantOutputMultipleClients = `// Code generated by codegen; DO NOT EDIT.
package services

import (
"github.com/cloudquery/codegen/interfaces"
"net/http"
)

//go:generate mockgen -package=mocks -destination=../mocks/interfaces.go -source=interfaces.go Client
type Client interface {
ListTables(context.Context) error
NewPager(context.Context) *interfaces.Pager[interfaces.Response]
}

//go:generate mockgen -package=mocks -destination=../mocks/interfaces.go -source=interfaces.go Client2
type Client2 interface {
ListTables(context.Context) error
}
`

func TestGenerate(t *testing.T) {
dir := t.TempDir()
err := Generate([]any{&Client{}}, dir,
Expand All @@ -73,3 +99,28 @@ func TestGenerate(t *testing.T) {
t.Errorf("unexpected diff (-got +want):\n%s", diff)
}
}

func TestGenerateMultipleClientsSamePackage(t *testing.T) {
dir := t.TempDir()
err := Generate([]any{&Client{}, &Client2{}}, dir,
WithIncludeFunc(func(m reflect.Method) bool {
return MethodHasAnyPrefix(m, []string{"ListTables"}) || MethodHasAnyPrefix(m, []string{"NewPager"})
}),
WithExtraImports(func(m reflect.Method) []string { return []string{"net/http"} }))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
fileName := path.Join(dir, "interfaces.go")
f, err := os.Open(fileName)
if err != nil {
t.Fatalf("failed to open file: %v", err)
}
defer f.Close()
b, err := io.ReadAll(f)
if err != nil {
t.Fatalf("failed to read file: %v", err)
}
if diff := cmp.Diff(string(b), wantOutputMultipleClients); diff != "" {
t.Errorf("unexpected diff (-got +want):\n%s", diff)
}
}
11 changes: 6 additions & 5 deletions interfaces/templates/service.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
package services

import (
"{{ .Import }}"
{{- range .ExtraImports }}
{{- range .Imports }}
"{{ . }}"
{{- end }}
)

//go:generate mockgen -package=mocks -destination=../mocks/{{.PackageName}}.go -source={{.PackageName}}.go {{.ClientName}}
type {{.ClientName}} interface {
{{ range .Clients }}
//go:generate mockgen -package=mocks -destination=../mocks/{{$.PackageName}}.go -source={{$.PackageName}}.go {{.Name}}
type {{.Name}} interface {
{{- range $sig := .Signatures }}
{{ $sig }}
{{- end }}
}
}
{{ end }}