Skip to content

Commit

Permalink
feat: add contributing guidelines and refactor config & utility funct…
Browse files Browse the repository at this point in the history
…ions

- Introduced .github/CONTRIBUTING.md for contribution guidelines.
- Updated AppConfig to use configfx.BaseConfig in pkg/app/config.go.
- Implemented LoadConfig function to initialize configuration in pkg/app/mod.go.
- Added ConfigLoader, env, and json parsers in pkg/bliss/configfx package.
- Refactored NewConfig to return pointer in pkg/bliss/httpfx/config.go.
- Renamed helper functions in pkg/bliss/lib for consistency.
- Extracted environment handling to pkg/bliss/lib/env.go.
- Introduced pkg/bliss/lib/paths.go for path handling utilities.
- Updated test cases to align with refactored environment functions.
  • Loading branch information
eser committed Aug 15, 2024
1 parent f4f2ddb commit 3653cf4
Show file tree
Hide file tree
Showing 17 changed files with 275 additions and 123 deletions.
64 changes: 64 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Contributing to [golang-service-template](./)

👍🎉 First off, thanks for taking the time to contribute! 🎉👍

The following is a set of guidelines for contributing to
`golang-service-template` and its packages, which are hosted in GitHub. These
are mostly guidelines, not strict rules. Use your best judgment and feel free to
propose changes to this document in a pull request.

## What Should I Know Before I Get Started?

### Code of Conduct

This project and everyone participating in it is governed by the
[@eser/directives](https://github.com/eser/stack/blob/dev/pkg/%40eser/directives/README.md).
By participating, you are expected to uphold this code. Please report
unacceptable behavior as in specified in the link.

### Technical Requirements

Just familiarity with Golang and Git.

### Conventions

Using existing precommit hooks should be fine for now. Please ensure your
submissions are formatted accordingly.

### Design Decisions

Before making significant changes, please open a new issue to discuss the
proposed changes and its design first.

## How Can I Contribute?

### Ways to Contribute

It is publicly open for any contribution. Here are some ideas you can begin
from:

- Reporting bugs
- Suggesting enhancements and new features
- Implementing performance improvements
- Improving documentation
- Submitting bug fixes
- Linking to your golang-service-template project

## Creating an Issue

- Check the
[GitHub Issues](https://github.com/eser/golang-service-template/issues) first
to avoid duplicating an existing issue.
- Use the issue tracker to ask questions, report problems or for discussion
related to the project.

## Submitting a Pull Request

- Adhere to
[@eser/directives](https://github.com/eser/stack/blob/dev/pkg/%40eser/directives/README.md)
- Fork the repo
- Make your changes in a new branch
- Provide tests for your changes, particularly for new features or fixes
- Push changes to your own fork
- Submit a pull request, linking it to the relevant issue. If an issue does not
exist, create one before submission.
2 changes: 1 addition & 1 deletion pkg/app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

type AppConfig struct {
configfx.Config
configfx.BaseConfig

AppName string `conf:"name" default:"go-service"`
Postgres struct {
Expand Down
8 changes: 6 additions & 2 deletions pkg/app/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"net/http"

"github.com/eser/go-service/pkg/bliss"
"github.com/eser/go-service/pkg/bliss/configfx"
"github.com/eser/go-service/pkg/bliss/httpfx"
"github.com/eser/go-service/pkg/bliss/httpfx/middlewares"
"github.com/eser/go-service/pkg/bliss/httpfx/modules/healthcheck"
Expand All @@ -13,17 +14,20 @@ import (

var appConfig = AppConfig{}

// configfx.Load(&appConfig)

var Module = fx.Module( //nolint:gochecknoglobals
"app",
fx.Invoke(
LoadConfig,
RegisterRoutes,
),
healthcheck.Module,
openapi.Module,
)

func LoadConfig(conf *configfx.ConfigLoader) {
conf.Load(&appConfig)
}

func RegisterRoutes(routes *httpfx.Router) {
routes.Use(middlewares.ErrorHandlerMiddleware())
routes.Use(middlewares.ResponseTimeMiddleware())
Expand Down
6 changes: 3 additions & 3 deletions pkg/bliss/configfx/envparser/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func trimExportPrefix(src []byte) []byte {
newSrc = src
}

return lib.TrimLeadingSpaceFromBytes(newSrc)
return lib.StringsTrimLeadingSpaceFromBytes(newSrc)
}

// locateKeyName locates and parses key name and returns rest of slice.
Expand All @@ -130,8 +130,8 @@ func locateKeyName(src []byte) (string, []byte, error) {
return "", nil, ErrZeroLengthString
}

key = lib.TrimTrailingSpace(key)
cutset := lib.TrimLeadingSpaceFromBytes(src[offset:])
key = lib.StringsTrimTrailingSpace(key)
cutset := lib.StringsTrimLeadingSpaceFromBytes(src[offset:])

return key, cutset, nil
}
Expand Down
112 changes: 112 additions & 0 deletions pkg/bliss/configfx/loader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package configfx

import (
"errors"
"fmt"
"reflect"

"github.com/eser/go-service/pkg/bliss/configfx/envparser"
"github.com/eser/go-service/pkg/bliss/configfx/jsonparser"
"github.com/eser/go-service/pkg/bliss/lib"
)

const (
tagConf = "conf"
)

var ErrNotStruct = errors.New("not a struct")

type ConfigLoader struct{}

type ConfigMeta struct {
Name string
Type reflect.Type
Children *[]ConfigMeta
}

func (dcl *ConfigLoader) TryLoadEnv(m *map[string]string) error {
env := lib.EnvGetCurrent()
filenames := lib.EnvAwareFilenames(env, ".env")

err := envparser.TryParseFiles(m, filenames...)
if err != nil {
return err //nolint:wrapcheck
}

lib.EnvOverrideVariables(m)

return nil
}

func (dcl *ConfigLoader) TryLoadJson(m *map[string]any) error {
env := lib.EnvGetCurrent()
filenames := lib.EnvAwareFilenames(env, "config.json")

err := jsonparser.TryParseFiles(m, filenames...)
if err != nil {
return err //nolint:wrapcheck
}

return nil
}

func reflectMeta(r reflect.Value) (*[]ConfigMeta, error) {
result := []ConfigMeta{}

if r.Kind() != reflect.Struct {
return nil, ErrNotStruct
}

for i := range r.NumField() {
fieldType := r.Type().Field(i)

if fieldType.Anonymous {
children, err := reflectMeta(r.Field(i))
if err != nil {
return nil, err
}

result = append(result, *children...)

continue
}

tag, ok := fieldType.Tag.Lookup(tagConf)
if !ok {
continue
}

result = append(result, ConfigMeta{
Name: tag,
Type: fieldType.Type,
})
}

return &result, nil
}

func (dcl *ConfigLoader) LoadMeta(i any) (*ConfigMeta, error) {
r := reflect.ValueOf(i).Elem()
children, err := reflectMeta(r)
if err != nil {
return nil, err
}

return &ConfigMeta{
Name: "root",
Children: children,
}, nil
}

func (dcl *ConfigLoader) Load(i any) error {
meta, err := dcl.LoadMeta(i)
if err != nil {
return err
}

for _, child := range *meta.Children {
fmt.Printf("fieldName: %s fieldType: %s\n", child.Name, child.Type.Name())
}

return nil
}
86 changes: 1 addition & 85 deletions pkg/bliss/configfx/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ package configfx

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

"github.com/eser/go-service/pkg/bliss/configfx/envparser"
"github.com/eser/go-service/pkg/bliss/configfx/jsonparser"
"go.uber.org/fx"
)

Expand All @@ -27,9 +22,7 @@ type Result struct {
ConfigLoader *ConfigLoader
}

type ConfigLoader struct{}

type Config struct {
type BaseConfig struct {
Env string `conf:"env"`

// AppName string `conf:"APP_NAME"`
Expand All @@ -41,83 +34,6 @@ type Config struct {
// DataConnstr string `conf:"DATA_CONNSTR"`
}

func GetCurrentEnv() string {
// FIXME(@eser) no need to use os.Lookupenv here
env := strings.ToLower(os.Getenv("ENV"))

if env == "" {
env = "development"
}

return env
}

func splitFilename(filename string) (string, string, string) {
dir, file := filepath.Split(filename)
ext := filepath.Ext(file)
rest := len(file) - len(ext)

if rest == 0 {
return dir, file, ""
}

return dir, file[:rest], ext
}

func GetFilenamesForEnv(env string, filename string) []string {
dirname, basename, ext := splitFilename(filename)

filenames := []string{
filename,
dirname + basename + "." + env + ext,
}

if env != "test" {
filenames = append(filenames, dirname+basename+".local"+ext)
}

filenames = append(filenames, dirname+basename+"."+env+".local"+ext)

return filenames
}

func OverrideWithSystemEnv(m *map[string]string) {
for _, e := range os.Environ() {
pair := strings.SplitN(e, "=", 2) //nolint:gomnd,mnd
(*m)[pair[0]] = pair[1]
}
}

func (dcl *ConfigLoader) TryLoadEnv(m *map[string]string) error {
env := GetCurrentEnv()
filenames := GetFilenamesForEnv(env, ".env")

err := envparser.TryParseFiles(m, filenames...)
if err != nil {
return err //nolint:wrapcheck
}

OverrideWithSystemEnv(m)

return nil
}

func (dcl *ConfigLoader) TryLoadJson(m *map[string]any) error {
env := GetCurrentEnv()
filenames := GetFilenamesForEnv(env, "config.json")

err := jsonparser.TryParseFiles(m, filenames...)
if err != nil {
return err //nolint:wrapcheck
}

return nil
}

func (dcl *ConfigLoader) Load(out *any) error {
return nil
}

func New() (Result, error) {
// envMap := map[string]string{
// "APP_NAME": "go-service",
Expand Down
16 changes: 8 additions & 8 deletions pkg/bliss/httpfx/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,38 +29,38 @@ type Config struct {
Addr string
}

func NewConfig() (Config, error) {
func NewConfig() (*Config, error) {
readHeaderTimeout, err := time.ParseDuration(DefaultReadHeaderTimeout)
if err != nil {
return Config{}, fmt.Errorf("error parsing read header timeout: %w", err)
return &Config{}, fmt.Errorf("error parsing read header timeout: %w", err)
}

readTimeout, err := time.ParseDuration(DefaultReadTimeout)
if err != nil {
return Config{}, fmt.Errorf("error parsing read timeout: %w", err)
return &Config{}, fmt.Errorf("error parsing read timeout: %w", err)
}

writeTimeout, err := time.ParseDuration(DefaultWriteTimeout)
if err != nil {
return Config{}, fmt.Errorf("error parsing write timeout: %w", err)
return &Config{}, fmt.Errorf("error parsing write timeout: %w", err)
}

idleTimeout, err := time.ParseDuration(DefaultIdleTimeout)
if err != nil {
return Config{}, fmt.Errorf("error parsing idle timeout: %w", err)
return &Config{}, fmt.Errorf("error parsing idle timeout: %w", err)
}

initializationTimeout, err := time.ParseDuration(DefaultInitializationTimeout)
if err != nil {
return Config{}, fmt.Errorf("error parsing initialization timeout: %w", err)
return &Config{}, fmt.Errorf("error parsing initialization timeout: %w", err)
}

gracefulShutdownTimeout, err := time.ParseDuration(DefaultGracefulShutdownTimeout)
if err != nil {
return Config{}, fmt.Errorf("error parsing graceful shutdown timeout: %w", err)
return &Config{}, fmt.Errorf("error parsing graceful shutdown timeout: %w", err)
}

return Config{
return &Config{
ReadHeaderTimeout: readHeaderTimeout,
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
Expand Down
Loading

0 comments on commit 3653cf4

Please sign in to comment.