Skip to content

Commit 14e92c1

Browse files
working feature of the dynconf lib test
1 parent 8ebd867 commit 14e92c1

28 files changed

+1913
-0
lines changed

.github/workflows/ci.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v3
14+
- name: Set up Go
15+
uses: actions/setup-go@v4
16+
with:
17+
go-version: '1.21'
18+
- name: Test
19+
run: |
20+
go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
21+
- name: Upload coverage
22+
uses: codecov/codecov-action@v3
23+
with:
24+
file: ./coverage.txt

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Your Name
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

cmd/examples/basic/main.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"errors" // Added this import
6+
"log"
7+
"time"
8+
9+
"github.com/samuelarogbonlo/dynconf/pkg/dynconf"
10+
)
11+
12+
type AppConfig struct {
13+
ServerPort int `json:"server_port"`
14+
Timeout time.Duration `json:"timeout"`
15+
}
16+
17+
func main() {
18+
ctx := context.Background()
19+
20+
cfg := dynconf.New[AppConfig](
21+
dynconf.WithValidation[AppConfig](func(old, new AppConfig) error {
22+
if new.ServerPort < 1024 {
23+
return errors.New("server port must be >= 1024")
24+
}
25+
return nil
26+
}),
27+
dynconf.WithRollback[AppConfig](true),
28+
)
29+
30+
// You might need to use Subscribe() instead of Watch() depending on the package version
31+
changes, err := cfg.Subscribe(ctx) // Changed Watch to Subscribe
32+
if err != nil {
33+
log.Fatal(err)
34+
}
35+
36+
go func() {
37+
for newCfg := range changes {
38+
log.Printf("Config updated: %+v", newCfg)
39+
}
40+
}()
41+
42+
// Application logic...
43+
select {}
44+
}

cmd/examples/multistore/main.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"errors"
6+
"log"
7+
"time"
8+
9+
"github.com/samuelarogbonlo/dynconf/pkg/dynconf"
10+
)
11+
12+
type DatabaseConfig struct {
13+
Host string `json:"host"`
14+
Port int `json:"port"`
15+
MaxConns int `json:"max_connections"`
16+
IdleTimeout time.Duration `json:"idle_timeout"`
17+
}
18+
19+
func main() {
20+
ctx := context.Background()
21+
22+
// Create file source
23+
fileSource, err := dynconf.NewFileSource[DatabaseConfig]("config.json")
24+
if err != nil {
25+
log.Fatal(err)
26+
}
27+
28+
// Create etcd source
29+
etcdSource, err := dynconf.NewEtcdSource[DatabaseConfig](
30+
[]string{"localhost:2379"},
31+
"/app/database",
32+
)
33+
if err != nil {
34+
log.Fatal(err)
35+
}
36+
37+
// Create config with sources
38+
cfg := dynconf.New[DatabaseConfig](
39+
// Try the basic Option approach
40+
dynconf.Option[DatabaseConfig](func(c *dynconf.Config[DatabaseConfig]) {
41+
c.AddSource(fileSource)
42+
c.AddSource(etcdSource)
43+
}),
44+
dynconf.WithValidation[DatabaseConfig](validateDatabase),
45+
dynconf.WithRollback[DatabaseConfig](true),
46+
)
47+
48+
changes, cleanup := cfg.Subscribe(ctx)
49+
defer cleanup()
50+
51+
go func() {
52+
for newCfg := range changes {
53+
log.Printf("Database config updated: %+v", newCfg)
54+
if err := updateDatabase(newCfg); err != nil {
55+
log.Printf("Error updating database: %v", err)
56+
}
57+
}
58+
}()
59+
60+
select {}
61+
}
62+
63+
func validateDatabase(old, new DatabaseConfig) error {
64+
if new.MaxConns <= 0 {
65+
return errors.New("max connections must be positive")
66+
}
67+
if new.IdleTimeout < time.Second {
68+
return errors.New("idle timeout must be at least 1 second")
69+
}
70+
return nil
71+
}
72+
73+
func updateDatabase(cfg DatabaseConfig) error {
74+
// Implementation to update database connection pool
75+
return nil
76+
}

cmd/examples/rollout/main.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"errors" // Added missing import
6+
"log"
7+
8+
"github.com/samuelarogbonlo/dynconf/pkg/dynconf"
9+
)
10+
11+
type FeatureConfig struct {
12+
Enabled bool `json:"enabled"`
13+
Percentage float64 `json:"percentage"`
14+
MaxRequests int `json:"max_requests"`
15+
}
16+
17+
func main() {
18+
ctx := context.Background()
19+
20+
cfg := dynconf.New[FeatureConfig]()
21+
22+
// Create validation function
23+
validateFunc := func(old, new FeatureConfig) error {
24+
return validateFeature(new)
25+
}
26+
27+
// Configure with validation
28+
cfg = dynconf.New[FeatureConfig](
29+
dynconf.WithValidation[FeatureConfig](validateFunc),
30+
dynconf.WithRollback[FeatureConfig](true),
31+
)
32+
33+
// Subscribe to changes instead of Watch
34+
changes, cleanup := cfg.Subscribe(ctx)
35+
defer cleanup()
36+
37+
// Create a rollout checker
38+
isEnabled := func(cfg FeatureConfig) bool {
39+
return cfg.Enabled && cfg.Percentage > 0
40+
}
41+
42+
go func() {
43+
for newCfg := range changes {
44+
if isEnabled(newCfg) {
45+
log.Printf("Applying feature config: %+v", newCfg)
46+
if err := applyFeature(newCfg); err != nil {
47+
log.Printf("Error applying feature: %v", err)
48+
}
49+
}
50+
}
51+
}()
52+
53+
select {}
54+
}
55+
56+
func validateFeature(cfg FeatureConfig) error {
57+
if cfg.Percentage < 0 || cfg.Percentage > 100 {
58+
return errors.New("percentage must be between 0 and 100")
59+
}
60+
if cfg.MaxRequests < 0 {
61+
return errors.New("max requests must be non-negative")
62+
}
63+
return nil
64+
}
65+
66+
func applyFeature(cfg FeatureConfig) error {
67+
// Implementation to apply feature configuration
68+
return nil
69+
}

docs/configuration-sources.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# docs/configuration-sources.md
2+
# Configuration Sources
3+
4+
DynConf supports multiple configuration sources:
5+
6+
## File Source
7+
8+
```go
9+
source, err := dynconf.NewFileSource[AppConfig]("config.json")
10+
cfg := dynconf.New[AppConfig](dynconf.WithSource[AppConfig](source))
11+
```
12+
13+
## Etcd Source
14+
15+
```go
16+
source, err := dynconf.NewEtcdSource[AppConfig]([]string{"localhost:2379"}, "/app/config")
17+
cfg := dynconf.New[AppConfig](dynconf.WithSource[AppConfig](source))
18+
```
19+
20+
## Consul Source
21+
22+
```go
23+
source, err := dynconf.NewConsulSource[AppConfig]("localhost:8500", "app/config")
24+
cfg := dynconf.New[AppConfig](dynconf.WithSource[AppConfig](source))
25+
```
26+

docs/contributing.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
3+
# docs/contributing.md
4+
# Contributing to DynConf
5+
6+
## Development Setup
7+
8+
1. Fork the repository
9+
2. Clone your fork:
10+
```bash
11+
git clone https://github.com/samuelarogbonlo/dynconf.git
12+
```
13+
14+
3. Install dependencies:
15+
```bash
16+
go mod download
17+
```
18+
19+
4. Run tests:
20+
```bash
21+
go test -v ./...
22+
```
23+
24+
## Pull Request Process
25+
26+
1. Create a new branch for your feature
27+
2. Add tests for new functionality
28+
3. Update documentation as needed
29+
4. Submit PR with description of changes
30+
31+
## Code Style
32+
33+
- Follow standard Go conventions
34+
- Use gofmt for formatting
35+
- Add comments for exported symbols

docs/getting-started.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# docs/getting-started.md
2+
# Getting Started with DynConf
3+
4+
## Installation
5+
6+
```bash
7+
go get github.com/samuelarogbonlo/dynconf
8+
```
9+
10+
## Basic Usage
11+
12+
1. Define your configuration type:
13+
14+
```go
15+
type AppConfig struct {
16+
ServerPort int `json:"server_port"`
17+
Timeout time.Duration `json:"timeout"`
18+
}
19+
```
20+
21+
2. Create a configuration instance:
22+
23+
```go
24+
cfg := dynconf.New[AppConfig](
25+
dynconf.WithValidation[AppConfig](validateConfig),
26+
dynconf.WithRollback[AppConfig](true),
27+
)
28+
```
29+
30+
3. Watch for changes:
31+
32+
```go
33+
changes, err := cfg.Watch(context.Background())
34+
if err != nil {
35+
log.Fatal(err)
36+
}
37+
38+
go func() {
39+
for newCfg := range changes {
40+
// Handle configuration updates
41+
}
42+
}()
43+
```

docs/metrics.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# docs/metrics.md
2+
# Metrics
3+
4+
DynConf provides Prometheus metrics for monitoring:
5+
6+
## Available Metrics
7+
8+
- `config_updates_total`: Counter of configuration updates
9+
- `config_version`: Gauge of current configuration version
10+
- `validation_errors_total`: Counter of validation errors
11+
- `rollbacks_total`: Counter of configuration rollbacks
12+
- `update_duration_seconds`: Histogram of update durations
13+
14+
## Usage
15+
16+
```go
17+
metrics := dynconf.NewMetrics("myapp")
18+
cfg.WithMetrics(metrics)
19+
```

0 commit comments

Comments
 (0)