Skip to content

Commit

Permalink
fix: 🐛 some bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mehdihadeli committed Sep 20, 2023
1 parent 52114b2 commit 8328644
Show file tree
Hide file tree
Showing 18 changed files with 183 additions and 137 deletions.
8 changes: 5 additions & 3 deletions internal/pkg/config/config_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ func BindConfigKey[T any](configKey string, environments ...environemnt.Environm
}

// https://articles.wesionary.team/environment-variable-configuration-in-your-golang-project-using-viper-4e8289ef664d
configPathFromEnv := viper.Get(constants.ConfigPath)
if configPathFromEnv != nil {
configPath = configPathFromEnv.(string)
// when we `Set` a viper with string value, we should get it from viper with `viper.GetString`, elsewhere we get empty string
// load `config path` from environment variable or viper internal registry
configPathFromEnv := viper.GetString(constants.ConfigPath)
if configPathFromEnv != "" {
configPath = configPathFromEnv
} else {
// https://stackoverflow.com/questions/31873396/is-it-possible-to-get-the-current-root-of-package-structure-as-a-string-in-golan
// https://stackoverflow.com/questions/18537257/how-to-get-the-directory-of-the-currently-running-file
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/config/configfx.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var ModuleFunc = func(e environemnt.Environment) fx.Option {
return fx.Module(
"configfx",
fx.Provide(func() environemnt.Environment {
return e
return environemnt.ConfigAppEnv(e)
}),
)
}
61 changes: 59 additions & 2 deletions internal/pkg/config/environemnt/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ package environemnt
import (
"log"
"os"
"path/filepath"
"strings"
"syscall"

"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/constants"

"emperror.dev/errors"
"github.com/joho/godotenv"
"github.com/spf13/viper"
)
Expand All @@ -32,9 +35,33 @@ func ConfigAppEnv(environments ...Environment) Environment {

// https://articles.wesionary.team/environment-variable-configuration-in-your-golang-project-using-viper-4e8289ef664d
// load environment variables form .env files to system environment variables, it just find `.env` file in our current `executing working directory` in our app for example `catalogs_service`
err := godotenv.Load()
err := loadEnvFilesRecursive()
if err != nil {
log.Println(".env file cannot be found.")
log.Printf(".env file cannot be found, err: %v", err)
}

// https://articles.wesionary.team/environment-variable-configuration-in-your-golang-project-using-viper-4e8289ef664d
// when we `Set` a viper with string value, we should get it from viper with `viper.GetString`, elsewhere we get empty string
// viper will get it from `os env` or viper `internal registry`
pn := viper.GetString(constants.PROJECT_NAME_ENV)
if pn != "" {
// set root working directory of our app in the viper
// https://stackoverflow.com/a/47785436/581476
wd, _ := os.Getwd()

for !strings.HasSuffix(wd, pn) {
wd = filepath.Dir(wd)
}

absRootDirectory, _ := filepath.Abs(wd)

// when we `Set` a viper with string value, we should get it from viper with `viper.GetString`, elsewhere we get empty string
viper.Set(constants.AppRootPath, absRootDirectory)

configPath := filepath.Join(absRootDirectory, "config")

// when we `Set` a viper with string value, we should get it from viper with `viper.GetString`, elsewhere we get empty string
viper.Set(constants.ConfigPath, configPath)
}

manualEnv := os.Getenv(constants.AppEnv)
Expand Down Expand Up @@ -64,3 +91,33 @@ func EnvString(key, fallback string) string {
}
return fallback
}

func loadEnvFilesRecursive() error {
// Start from the current working directory
dir, err := os.Getwd()
if err != nil {
return err
}

// Keep traversing up the directory hierarchy until you find an ".env" file
for {
envFilePath := filepath.Join(dir, ".env")
err := godotenv.Load(envFilePath)

if err == nil {
// .env file found and loaded
return nil
}

// Move up one directory level
parentDir := filepath.Dir(dir)
if parentDir == dir {
// Reached the root directory, stop searching
break
}

dir = parentDir
}

return errors.New(".env file not found in the project hierarchy")
}
33 changes: 0 additions & 33 deletions internal/pkg/fxapp/application_builder.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package fxapp

import (
"os"
"path/filepath"
"strings"

"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/config/environemnt"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/constants"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/fxapp/contracts"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/logger"
loggerConfig "github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/logger/config"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/logger/logrous"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/logger/models"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/logger/zap"

"github.com/spf13/viper"
"go.uber.org/fx"
)

Expand All @@ -29,8 +23,6 @@ type applicationBuilder struct {
func NewApplicationBuilder(environments ...environemnt.Environment) contracts.ApplicationBuilder {
env := environemnt.ConfigAppEnv(environments...)

setConfigPath()

var logger logger.Logger
logoption, err := loggerConfig.ProvideLogConfig(env)
if err != nil || logoption == nil {
Expand All @@ -44,31 +36,6 @@ func NewApplicationBuilder(environments ...environemnt.Environment) contracts.Ap
return &applicationBuilder{logger: logger, environment: env}
}

func setConfigPath() {
// https://stackoverflow.com/a/47785436/581476
wd, _ := os.Getwd()

// https://articles.wesionary.team/environment-variable-configuration-in-your-golang-project-using-viper-4e8289ef664d
// get from `os env` or viper `internal registry`
pn := viper.Get(constants.PROJECT_NAME_ENV)
if pn == nil {
return
}
for !strings.HasSuffix(wd, pn.(string)) {
wd = filepath.Dir(wd)
}

// Get the absolute path of the executed project directory
absCurrentDir, _ := filepath.Abs(wd)

viper.Set(constants.AppRootPath, absCurrentDir)

// Get the path to the "config" folder within the project directory
configPath := filepath.Join(absCurrentDir, "config")

viper.Set(constants.ConfigPath, configPath)
}

func (a *applicationBuilder) ProvideModule(module fx.Option) {
a.options = append(a.options, module)
}
Expand Down
2 changes: 2 additions & 0 deletions internal/pkg/fxapp/contracts/application_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
)

type ApplicationBuilder interface {
// ProvideModule register modules directly instead and modules should not register with `provided` function
ProvideModule(module fx.Option)
// Provide register functions constructors as dependency resolver
Provide(constructors ...interface{})
Decorate(constructors ...interface{})
Build() Application
Expand Down
51 changes: 38 additions & 13 deletions internal/pkg/fxapp/test/test_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package test

import (
"context"
"os"

"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/config/environemnt"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/constants"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/fxapp/contracts"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/logger"

"github.com/spf13/viper"
"go.uber.org/fx"
"go.uber.org/fx/fxtest"
)
Expand Down Expand Up @@ -61,16 +64,8 @@ func (a *testApplication) RegisterHook(function interface{}) {
}

func (a *testApplication) Run() {
// build phase of container will do in this stage, containing provides and invokes but app not started yet and will be started in the future with `fxApp.Register`
fxTestApp := CreateFxTestApp(
a.tb,
a.provides,
a.decorates,
a.invokes,
a.options,
a.logger,
a.env,
)
fxTestApp := a.createFxTest()

// running phase will do in this stage and all register event hooks like OnStart and OnStop
// instead of run for handling start and stop and create a ctx and cancel we can handle them manually with appconfigfx.start and appconfigfx.stop
// https://github.com/uber-go/fx/blob/v1.20.0/app.go#L573
Expand All @@ -79,10 +74,9 @@ func (a *testApplication) Run() {

func (a *testApplication) Start(ctx context.Context) error {
// build phase of container will do in this stage, containing provides and invokes but app not started yet and will be started in the future with `fxApp.Register`
fxApp := CreateFxTestApp(a.tb, a.provides, a.decorates, a.invokes, a.options, a.logger, a.env)
a.fxtestApp = fxApp
fxTestApp := a.createFxTest()

return fxApp.Start(ctx)
return fxTestApp.Start(ctx)
}

func (a *testApplication) Stop(ctx context.Context) error {
Expand All @@ -98,3 +92,34 @@ func (a *testApplication) Wait() <-chan fx.ShutdownSignal {
}
return a.fxtestApp.Wait()
}

func (a *testApplication) createFxTest() *fxtest.App {
a.fixTestEnvironmentWorkingDirectory()

// build phase of container will do in this stage, containing provides and invokes but app not started yet and will be started in the future with `fxApp.Register`
fxTestApp := CreateFxTestApp(
a.tb,
a.provides,
a.decorates,
a.invokes,
a.options,
a.logger,
a.env,
)
a.fxtestApp = fxTestApp

return fxTestApp
}

func (a *testApplication) fixTestEnvironmentWorkingDirectory() {
currentWD, _ := os.Getwd()
a.logger.Infof("Current test working directory is: %s", currentWD)

rootDir := viper.GetString(constants.AppRootPath)
if rootDir != "" {
_ = os.Chdir(rootDir)

newWD, _ := os.Getwd()
a.logger.Infof("New test working directory is: %s", newWD)
}
}
24 changes: 17 additions & 7 deletions internal/pkg/migration/gomigrate/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,20 +106,30 @@ func (m *goMigratePostgresMigrator) Down(_ context.Context, version uint) error
}

func (m *goMigratePostgresMigrator) executeCommand(command migration.CommandType, version uint) error {
var err error
switch command {
case migration.Up:
if version == 0 {
return m.migration.Up()
err = m.migration.Up()
} else {
err = m.migration.Migrate(version)
}

return m.migration.Migrate(version)
case migration.Down:
if version == 0 {
return m.migration.Down()
err = m.migration.Down()
} else {
err = m.migration.Migrate(version)
}

return m.migration.Migrate(version)
default:
return errors.New("invalid migration direction")
err = errors.New("invalid migration direction")
}

if err == migrate.ErrNoChange {
return nil
}
if err != nil {
return errors.WrapIf(err, "failed to migrate database")
}

return nil
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package test

import (
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/constants"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/fxapp/contracts"
"github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/fxapp/test"
constants2 "github.com/mehdihadeli/go-ecommerce-microservices/internal/services/catalogreadservice/internal/shared/constants"

"github.com/spf13/viper"
"go.uber.org/fx/fxtest"
)

Expand All @@ -16,9 +13,6 @@ type CatalogsReadTestApplicationBuilder struct {
}

func NewCatalogsReadTestApplicationBuilder(tb fxtest.TB) *CatalogsReadTestApplicationBuilder {
// set viper internal registry, in real app we read it from `.env` file in current `executing working directory` for example `catalogs_service`
viper.Set(constants.PROJECT_NAME_ENV, constants2.PROJECT_NAME)

return &CatalogsReadTestApplicationBuilder{
ApplicationBuilder: test.NewTestApplicationBuilder(tb),
tb: tb,
Expand Down

This file was deleted.

10 changes: 10 additions & 0 deletions internal/services/catalog_write_service/config/config.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,15 @@
},
"eventStoreDbOptions": {
"connectionString": "esdb://localhost:2113?tls=false"
},
"migrationOptions": {
"host": "localhost",
"port": 5432,
"user": "postgres",
"password": "postgres",
"dbName": "catalogs_service",
"sslMode": false,
"migrationsDir": "db/migrations/goose-migrate",
"skipMigration": false
}
}
9 changes: 3 additions & 6 deletions internal/services/catalog_write_service/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ require (
)

require (
ariga.io/atlas-go-sdk v0.0.0-20230709063453-1058d6508503 // indirect
ariga.io/atlas-provider-gorm v0.1.0 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/ClickHouse/ch-go v0.58.2 // indirect
Expand All @@ -49,7 +47,6 @@ require (
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
github.com/ahmetb/go-linq/v3 v3.2.0 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/alecthomas/kong v0.8.0 // indirect
github.com/alexflint/go-filemutex v1.2.0 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
Expand Down Expand Up @@ -78,7 +75,6 @@ require (
github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/go-testfixtures/testfixtures/v3 v3.9.0 // indirect
github.com/goccy/go-reflect v1.2.0 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect
Expand All @@ -91,6 +87,8 @@ require (
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/imkira/go-interpol v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
Expand Down Expand Up @@ -178,6 +176,7 @@ require (
go.opentelemetry.io/otel/exporters/zipkin v1.17.0 // indirect
go.opentelemetry.io/otel/sdk v1.17.0 // indirect
go.opentelemetry.io/otel/sdk/metric v0.40.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/dig v1.17.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.25.0 // indirect
Expand All @@ -191,9 +190,7 @@ require (
golang.org/x/tools v0.13.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gorm.io/driver/mysql v1.5.1 // indirect
gorm.io/driver/postgres v1.5.2 // indirect
gorm.io/driver/sqlite v1.5.2 // indirect
mellium.im/sasl v0.3.1 // indirect
moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e // indirect
)
Expand Down
Loading

0 comments on commit 8328644

Please sign in to comment.