Skip to content

Commit

Permalink
Refactoring, go version up, dependencies update
Browse files Browse the repository at this point in the history
  • Loading branch information
smgladkovskiy committed Oct 10, 2024
1 parent 5100f0f commit f60035e
Show file tree
Hide file tree
Showing 25 changed files with 430 additions and 332 deletions.
32 changes: 0 additions & 32 deletions .circleci/config.yml

This file was deleted.

36 changes: 36 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

name: Go

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:

test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'

- name: Install dependencies
run: go mod download

- name: Test
run: go test -cover -covermode=atomic -coverprofile=coverage.txt -coverpkg=./... -race -v ./...

- name: Upload results to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
5 changes: 0 additions & 5 deletions Dockerfile

This file was deleted.

17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Golang Microservice configuration module
----------------------------------------

[![CircleCI](https://circleci.com/gh/spacetab-io/configuration-go.svg?style=shield)](https://circleci.com/gh/spacetab-io/configuration-go) [![codecov](https://codecov.io/gh/spacetab-io/configuration-go/graph/badge.svg)](https://codecov.io/gh/spacetab-io/configuration-go)
[![codecov](https://codecov.io/gh/spacetab-io/configuration-go/graph/badge.svg)](https://codecov.io/gh/spacetab-io/configuration-go)

Configuration module for microservices written on Go.
Preserves [corporate standards for services configuration](https://confluence.teamc.io/pages/viewpage.action?pageId=4227704).
Expand All @@ -25,20 +25,21 @@ Some agreements:

1. Configuration must be declared as struct and reveals yaml structure
2. Default config folder: `./configuration`. If you need to override, pass your path in `ReadConfig` function
3. Stage is passed as `stage.Interface` implementation. In example below stageEnv is used to pass stage through env variable `STAGE`.
3. Stage is passed as `config.Stageable` implementation. In example below stageEnv is used to pass stage through env variable `STAGE`.

Code example:

```go
package main

import (
"context"
"fmt"
"log"

config "github.com/spacetab-io/configuration-go"
"github.com/spacetab-io/configuration-go/stage"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
)

// ConfigStruct is your app config structure. This must be related to yaml config file structure.
Expand Down Expand Up @@ -68,17 +69,17 @@ type ConfigStruct struct {
}

func main() {
// config.Read receives stage as stage.Interface implementation.
// config.Read receives stage as config.Stageable implementation.
// You can use envStage to pass stage name via ENV param STAGE.
// In NewEnvStage you can pass fallback value if STAGE param is empty.
envStage := stage.NewEnvStage("development")
envStage := config.NewEnvStage("development")
// Reading ALL config files in defaults configuration folder and recursively merge them with STAGE configs
configBytes, err := config.Read(envStage, "./configuration", true)
configBytes, err := config.Read(context.TODO(), envStage, config.WithConfigPath("./configuration"))
if err != nil {
log.Fatalf("config reading error: %+v", err)
}

cfg := ConfigStruct{}
var cfg ConfigStruct
// unmarshal config into Config structure
err = yaml.Unmarshal(configBytes, &cfg)
if err != nil {
Expand All @@ -93,7 +94,7 @@ func main() {

The MIT License

Copyright © 2021 SpaceTab.io, Inc. https://spacetab.io
Copyright © 2024 SpaceTab.io, Inc. https://spacetab.io

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "
Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,
Expand Down
2 changes: 1 addition & 1 deletion config_examples/configuration/dev/service.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dev:
debug: true
string_test: null
string_test: ""
bool_test: false
33 changes: 33 additions & 0 deletions env_stage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package config

import (
"os"
)

type Stageable interface {
Name() StageName
}

type EnvStage StageName

const ENVStageKey = "STAGE"

var _ Stageable = (*EnvStage)(nil)

func NewEnvStage(fallback string) Stageable {
value, ok := os.LookupEnv(ENVStageKey)
if !ok {
return EnvStage(fallback)
}

return EnvStage(value)
}

// Name Loads stage name with fallback to 'dev'.
func (s EnvStage) Name() StageName {
if s == "" {
return StageNameDefaults
}

return StageName(s)
}
39 changes: 39 additions & 0 deletions env_stage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package config_test

import (
"os"
"testing"

"github.com/spacetab-io/configuration-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestNewEnvStage(t *testing.T) {
envStage := config.NewEnvStage("dev")
assert.Equal(t, config.EnvStage("dev"), envStage)

require.NoError(t, os.Setenv(config.ENVStageKey, "prod"))
envStage = config.NewEnvStage("dev")
assert.Equal(t, config.EnvStage("prod"), envStage)
require.NoError(t, os.Unsetenv(config.ENVStageKey))
}

func TestEnvStage_Get(t *testing.T) {
t.Parallel()

envStage := config.NewEnvStage("dev")

assert.Equal(t, config.StageName("dev"), envStage.Name())
}

func TestEnvStage_Name(t *testing.T) {
t.Parallel()

envStage := config.NewEnvStage("dev")

assert.Equal(t, "dev", envStage.Name().String())

envStage = config.EnvStage("")
assert.Equal(t, config.StageNameDefaults, envStage.Name())
}
13 changes: 9 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
module github.com/spacetab-io/configuration-go

go 1.14
go 1.22

require (
github.com/imdario/mergo v0.3.12
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v2 v2.4.0
dario.cat/mergo v1.0.1
github.com/stretchr/testify v1.9.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
)
21 changes: 8 additions & 13 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
26 changes: 26 additions & 0 deletions logging.go
Original file line number Diff line number Diff line change
@@ -1 +1,27 @@
package config

import (
"context"
)

type Logger interface {
Debug(context.Context, string, ...any)
Warn(context.Context, string, ...any)
Error(context.Context, string, ...any)
}

var _ Logger = (*noOpLogger)(nil)

type noOpLogger struct{}

func (n noOpLogger) Debug(ctx context.Context, msg string, args ...any) {
return
}

func (n noOpLogger) Error(ctx context.Context, msg string, args ...any) {
return
}

func (n noOpLogger) Warn(ctx context.Context, msg string, args ...any) {
return
}
33 changes: 33 additions & 0 deletions merger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package config

import "sync"

const defaultConfigPath = "./configuration"

type merger struct {
logger Logger
stage Stageable
cfgPath string
mu sync.RWMutex
configs map[StageName]map[string]any
fileList map[StageName][]string
}

func newMerger(opts ...Option) (*merger, error) {
mc := merger{
logger: noOpLogger{},
mu: sync.RWMutex{},
stage: EnvStage(StageNameDefaults),
cfgPath: defaultConfigPath,
fileList: make(map[StageName][]string),
configs: make(map[StageName]map[string]any),
}

for _, opt := range opts {
if err := opt(&mc); err != nil {
return nil, err
}
}

return &mc, nil
}
59 changes: 59 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package config

import (
"errors"
"fmt"
"os"
"strings"
)

type Option func(*merger) error

var (
ErrLoggerIsEmpty = fmt.Errorf("logger is empty")
ErrEmptyConfigPath = errors.New("empty config path")
ErrConfigPath = errors.New("config path error")
ErrStageIsEmpty = errors.New("stage data is empty")
)

func WithLogger(logger Logger) Option {
return func(mc *merger) error {
if logger == Logger(nil) {
return ErrLoggerIsEmpty
}

mc.logger = logger

return nil
}
}

func withStageName(stage Stageable) Option {
return func(mc *merger) error {
if stage == nil {
return ErrStageIsEmpty
}

mc.stage = stage

return nil
}
}

func WithConfigPath(cfgPath string) Option {
return func(mc *merger) error {
if cfgPath == "" {
return ErrEmptyConfigPath
}

cfgPath = strings.TrimRight(cfgPath, "/")

if _, err := os.Stat(cfgPath); os.IsNotExist(err) {
return fmt.Errorf("%w: %s", ErrConfigPath, err)
}

mc.cfgPath = cfgPath

return nil
}
}
Loading

0 comments on commit f60035e

Please sign in to comment.