From 31a21ac7771da958e2b0e1e1326839ef47da123d Mon Sep 17 00:00:00 2001 From: Miroslav Cvetic Date: Wed, 1 Jul 2026 16:46:26 +0200 Subject: [PATCH 1/3] feat: add region support to config, generator, templates and testapi --- Makefile | 5 +++ config/config_test.go | 32 +++++++++++++++---- config/sampleconfig.yaml | 1 + config/vo.go | 1 + erm/space.go | 13 +++++--- erm/space_test.go | 44 ++++++++++++++++++++++++++ erm/templates/contentful_vo_lib.gotmpl | 11 ++++--- main.go | 4 ++- test/testapi/gocontentfulvolib.go | 8 +++-- 9 files changed, 100 insertions(+), 19 deletions(-) create mode 100644 erm/space_test.go diff --git a/Makefile b/Makefile index aae5ed5..ee434de 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,11 @@ lint.fix: testapi: @go run ./main.go -exportfile ./test/test-space-export.json ./test/testapi +.PHONY: testapi-region +## run api tests with EU region +testapi-region: + @go run ./main.go -exportfile ./test/test-space-export.json -region eu ./test/testapi + .PHONY: test ## Run tests test: testapi diff --git a/config/config_test.go b/config/config_test.go index cd4c636..f66ffbb 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,16 +1,34 @@ package config import ( + "os" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestConfigFromYAML(t *testing.T) { - config, err := LoadConfigFromYAML("./sampleconfig.yaml") - require.NoError(t, err) - require.Equal(t, "abc123", config.SpaceID) - require.Equal(t, "dev", config.Environment) - require.Equal(t, "v1.0.19", config.RequireVersion) - require.Len(t, config.ContentTypes, 2) +func TestLoadConfigFromYAML(t *testing.T) { + t.Run("full config with region", func(t *testing.T) { + cfg, err := LoadConfigFromYAML("./sampleconfig.yaml") + require.NoError(t, err) + require.Equal(t, "abc123", cfg.SpaceID) + require.Equal(t, "dev", cfg.Environment) + require.Equal(t, "v1.0.19", cfg.RequireVersion) + require.Len(t, cfg.ContentTypes, 2) + assert.Equal(t, "eu", cfg.Region) + }) + t.Run("region defaults to empty string when absent", func(t *testing.T) { + f, err := os.CreateTemp("", "gocontentful-test-*.yaml") + require.NoError(t, err) + defer os.Remove(f.Name()) + _, err = f.WriteString("spaceId: abc123\n") + require.NoError(t, err) + require.NoError(t, f.Close()) + + cfg, err := LoadConfigFromYAML(f.Name()) + require.NoError(t, err) + require.Equal(t, "abc123", cfg.SpaceID) + assert.Equal(t, "", cfg.Region) + }) } diff --git a/config/sampleconfig.yaml b/config/sampleconfig.yaml index f83a6bb..ea86480 100644 --- a/config/sampleconfig.yaml +++ b/config/sampleconfig.yaml @@ -1,3 +1,4 @@ +region: eu spaceId: "abc123" environment: "dev" exportFile: "foo.json" diff --git a/config/vo.go b/config/vo.go index 7a37ca2..de0c462 100644 --- a/config/vo.go +++ b/config/vo.go @@ -7,4 +7,5 @@ type Config struct { ContentTypes []string `json:"contentTypes,omitempty" yaml:"contentTypes,omitempty"` PathTargetPackage string `json:"pathTargetPackage,omitempty" yaml:"pathTargetPackage,omitempty"` RequireVersion string `json:"requireVersion,omitempty" yaml:"requireVersion,omitempty"` + Region string `json:"region,omitempty" yaml:"region,omitempty"` } diff --git a/erm/space.go b/erm/space.go index 329e6c5..3236b54 100644 --- a/erm/space.go +++ b/erm/space.go @@ -25,6 +25,7 @@ type spaceConf struct { ContentTypes []ContentType `yaml:"contentTypes"` ContentType ContentType `yaml:"contentType"` Version string `yaml:"version"` + Region string `yaml:"region"` } // GetLocales retrieves locale definition from Contentful @@ -82,7 +83,7 @@ func getContentTypes(ctx context.Context, cma *contentful.Contentful, spaceID st return } -func getData(ctx context.Context, spaceID, cmaKey, environment, exportFile string, flagContentTypes []string) ( +func getData(ctx context.Context, spaceID, cmaKey, environment, exportFile string, flagContentTypes []string, region string) ( finalContentTypes []ContentType, locales []Locale, err error, ) { var contentTypes []ContentType @@ -100,7 +101,7 @@ func getData(ctx context.Context, spaceID, cmaKey, environment, exportFile strin locales = export.Locales } else { // Get client - CMA := contentful.NewCMA(cmaKey) + CMA := contentful.NewCMA(cmaKey).SetRegion(contentful.Region(region)) CMA.Debug = false if environment != "" { CMA.Environment = environment @@ -141,8 +142,11 @@ func getData(ctx context.Context, spaceID, cmaKey, environment, exportFile strin } // GenerateAPI calls the generators -func GenerateAPI(ctx context.Context, dir, packageName, spaceID, cmaKey, environment, exportFile string, flagContentTypes []string, version string) error { - contentTypes, locales, errGetData := getData(ctx, spaceID, cmaKey, environment, exportFile, flagContentTypes) +func GenerateAPI(ctx context.Context, dir, packageName, spaceID, cmaKey, environment, exportFile string, flagContentTypes []string, version string, region string) error { + if _, err := contentful.ParseRegion(region); err != nil { + return err + } + contentTypes, locales, errGetData := getData(ctx, spaceID, cmaKey, environment, exportFile, flagContentTypes, region) if errGetData != nil { return errors.Wrap(errGetData, "could not get data") } @@ -160,6 +164,7 @@ func GenerateAPI(ctx context.Context, dir, packageName, spaceID, cmaKey, environ Locales: locales, ContentTypes: contentTypes, Version: version, + Region: region, } return generateCode(conf) } diff --git a/erm/space_test.go b/erm/space_test.go new file mode 100644 index 0000000..19c67a4 --- /dev/null +++ b/erm/space_test.go @@ -0,0 +1,44 @@ +package erm + +import ( + "context" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const testExportFile = "../test/test-space-export.json" + +func TestGenerateAPI_EmbedRegionEU(t *testing.T) { + dir := t.TempDir() + err := GenerateAPI(context.Background(), dir, "testpkg", "", "", "", testExportFile, nil, "test", "eu") + require.NoError(t, err) + + content, err := os.ReadFile(filepath.Join(dir, "testpkg", "gocontentfulvolib.go")) + require.NoError(t, err) + + src := string(content) + assert.True(t, strings.Contains(src, `.SetRegion("eu")`), "generated lib should call SetRegion(\"eu\")") +} + +func TestGenerateAPI_InvalidRegion(t *testing.T) { + err := GenerateAPI(context.Background(), t.TempDir(), "testpkg", "", "", "", testExportFile, nil, "test", "ap") + require.Error(t, err) + assert.ErrorContains(t, err, "unknown region") +} + +func TestGenerateAPI_EmbedRegionEmpty(t *testing.T) { + dir := t.TempDir() + err := GenerateAPI(context.Background(), dir, "testpkg", "", "", "", testExportFile, nil, "test", "") + require.NoError(t, err) + + content, err := os.ReadFile(filepath.Join(dir, "testpkg", "gocontentfulvolib.go")) + require.NoError(t, err) + + src := string(content) + assert.False(t, strings.Contains(src, `.SetRegion(`), "generated lib should not call SetRegion for default region") +} diff --git a/erm/templates/contentful_vo_lib.gotmpl b/erm/templates/contentful_vo_lib.gotmpl index a314b0e..01f7b78 100644 --- a/erm/templates/contentful_vo_lib.gotmpl +++ b/erm/templates/contentful_vo_lib.gotmpl @@ -751,7 +751,7 @@ func NewOfflineContentfulClient(file []byte, logFn func(fields map[string]interf } cc := &ContentfulClient{ clientMode: ClientModeCDA, - Client: contentful.NewCDA(""), + Client: contentful.NewCDA(""){{ if .Region }}.SetRegion("{{ .Region }}"){{ end }}, Cache: &ContentfulCache{ contentTypes: []string{}, idContentTypeMap: map[string]string{}, @@ -1864,16 +1864,19 @@ func (cc *ContentfulClient) entryMapForContentTypeIsNil(contentType string) bool } func getContentfulAPIClient(clientMode ClientMode, clientKey string) (*contentful.Contentful, error) { + var c *contentful.Contentful switch clientMode { case ClientModeCDA: - return contentful.NewCDA(clientKey), nil + c = contentful.NewCDA(clientKey) case ClientModeCPA: - return contentful.NewCPA(clientKey), nil + c = contentful.NewCPA(clientKey) case ClientModeCMA: - return contentful.NewCMA(clientKey), nil + c = contentful.NewCMA(clientKey) default: return nil, errors.New("NewContentfulClient: Unknown ClientMode") } + {{ if .Region }}c.SetRegion("{{ .Region }}") + {{ end }}return c, nil } func (cc *ContentfulClient) GetSpaceID() string { diff --git a/main.go b/main.go index e453272..33e4118 100644 --- a/main.go +++ b/main.go @@ -67,6 +67,7 @@ func main() { flagEnvironment := flag.String("environment", "", "[Optional] Contentful space environment") flagGenerateFromExport := flag.String("exportfile", "", "Space export file to generate the API from") flagContentTypes := flag.String("contenttypes", "", "[Optional] Content type IDs to parse, comma separated") + flagRegion := flag.String("region", "", "[Optional] Contentful infrastructure region (e.g. eu)") flagVersion := flag.Bool("version", false, "Print version and exit") flagHelp := flag.Bool("help", false, "Print version and exit") flag.Parse() @@ -95,6 +96,7 @@ func main() { SpaceID: *flagSpaceID, Environment: *flagEnvironment, ExportFile: *flagGenerateFromExport, + Region: *flagRegion, } if *flagContentTypes != "" { conf.ContentTypes = strings.Split(*flagContentTypes, ",") @@ -140,7 +142,7 @@ func main() { } } - err = erm.GenerateAPI(context.Background(), filepath.Dir(path), packageName, conf.SpaceID, cmaKey, conf.Environment, conf.ExportFile, cleanContentTypes, VERSION) + err = erm.GenerateAPI(context.Background(), filepath.Dir(path), packageName, conf.SpaceID, cmaKey, conf.Environment, conf.ExportFile, cleanContentTypes, VERSION, conf.Region) if err != nil { fatal("Something went horribly wrong...", err) } diff --git a/test/testapi/gocontentfulvolib.go b/test/testapi/gocontentfulvolib.go index 9cb5b29..9aea08a 100644 --- a/test/testapi/gocontentfulvolib.go +++ b/test/testapi/gocontentfulvolib.go @@ -1898,16 +1898,18 @@ func (cc *ContentfulClient) entryMapForContentTypeIsNil(contentType string) bool } func getContentfulAPIClient(clientMode ClientMode, clientKey string) (*contentful.Contentful, error) { + var c *contentful.Contentful switch clientMode { case ClientModeCDA: - return contentful.NewCDA(clientKey), nil + c = contentful.NewCDA(clientKey) case ClientModeCPA: - return contentful.NewCPA(clientKey), nil + c = contentful.NewCPA(clientKey) case ClientModeCMA: - return contentful.NewCMA(clientKey), nil + c = contentful.NewCMA(clientKey) default: return nil, errors.New("NewContentfulClient: Unknown ClientMode") } + return c, nil } func (cc *ContentfulClient) GetSpaceID() string { From 9ee161d5b694678cced5e89d619d35910b61ac67 Mon Sep 17 00:00:00 2001 From: Miroslav Cvetic Date: Thu, 2 Jul 2026 09:38:52 +0200 Subject: [PATCH 2/3] fix: update contentful dependency to v0.6.3 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 77e4e28..78c6e61 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/foomo/gocontentful go 1.24.0 require ( - github.com/foomo/contentful v0.6.0 + github.com/foomo/contentful v0.6.3 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index 7c23985..cb9cce1 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/aoliveti/curling v1.1.0/go.mod h1:xoDmoUg9vX3pMTltyG/rp9tFtIlweL2QeCJ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/foomo/contentful v0.6.0 h1:k9VOQj1ZxSbl5HR2oBvunNeuqTW9U48yAz6jYeDxYdE= -github.com/foomo/contentful v0.6.0/go.mod h1:xJ09xn+hTb5RKFyYL8vscxBh+DSH1wRzOljc9paEpp8= +github.com/foomo/contentful v0.6.3 h1:KlP4nYeV4Y3YlffYaz6t6xJ8CpF8ce/yA70j41YyOAY= +github.com/foomo/contentful v0.6.3/go.mod h1:xJ09xn+hTb5RKFyYL8vscxBh+DSH1wRzOljc9paEpp8= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= From 15eb3f4210932ad10100516e43cdfbd4e3569d8c Mon Sep 17 00:00:00 2001 From: Miroslav Cvetic Date: Thu, 2 Jul 2026 09:45:30 +0200 Subject: [PATCH 3/3] fix: use TempDir for temporary file creation in config tests --- config/config_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/config_test.go b/config/config_test.go index f66ffbb..3694586 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -19,9 +19,8 @@ func TestLoadConfigFromYAML(t *testing.T) { assert.Equal(t, "eu", cfg.Region) }) t.Run("region defaults to empty string when absent", func(t *testing.T) { - f, err := os.CreateTemp("", "gocontentful-test-*.yaml") + f, err := os.CreateTemp(t.TempDir(), "gocontentful-test-*.yaml") require.NoError(t, err) - defer os.Remove(f.Name()) _, err = f.WriteString("spaceId: abc123\n") require.NoError(t, err) require.NoError(t, f.Close())