From a966b2b951bf5d43d7c6f30958dcdf6757b20434 Mon Sep 17 00:00:00 2001 From: Kuisong Tong Date: Wed, 21 Feb 2024 19:04:05 -0800 Subject: [PATCH] Add ContinueOnError (#161) so watcher can continue watching even the loader fails to load the configuration --- .github/workflows/release.yml | 28 ++++++++++------------------ CHANGELOG.md | 7 +++++++ config.go | 18 +++++++++++++----- config_test.go | 35 +++++++++++++++++++++++++++++++++++ go.mod | 2 ++ option.go | 14 ++++++++++++++ 6 files changed, 81 insertions(+), 23 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 833f5da4..cbfe0c44 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,24 +45,16 @@ jobs: name: "v${{ steps.query-release-info.outputs.version }}", body: `${{ steps.query-release-info.outputs.release-notes }}` }) - - tag: - strategy: - matrix: - module: [ 'provider/file', 'provider/pflag', 'provider/appconfig', 'provider/azappconfig', 'provider/secretmanager' ] - name: Submodules - needs: release - if: ${{ needs.release.steps.create-release.outcome == 'success' }} - runs-on: ubuntu-latest - steps: - - name: Create tag + - name: Tag Submodules uses: actions/github-script@v7 with: script: | - ref = "refs/tags/${{ matrix.module }}/v${{ needs.release.steps.query-release-info.outputs.version }}" - github.rest.git.createRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: ref, - sha: context.sha - }) + const modules = [ 'provider/file', 'provider/pflag', 'provider/appconfig', 'provider/azappconfig', 'provider/secretmanager' ] + for (const module of modules) { + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: "refs/tags/${{ module }}/v${{ steps.query-release-info.outputs.version }}", + sha: context.sha + }) + } diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d75ec73..d531d119 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,16 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [0.6.2] - 2024-02-21 + +### Fixed + +- Add ContinueOnError so watcher can continue watching even the loader fails to load the configuration (#161). + ## [0.6.1] - 2024-02-21 ### Changed + - merge loader into providers even it fails the loading. Developers can ignore the loading error and wait for the watching to get latest configuration (#159). diff --git a/config.go b/config.go index 07781dac..5703c533 100644 --- a/config.go +++ b/config.go @@ -82,13 +82,25 @@ func New(opts ...Option) Config { // // This method can be called multiple times but it is not concurrency-safe. // It panics if loader is nil. -func (c Config) Load(loader Loader) error { +func (c Config) Load(loader Loader, opts ...LoadOption) error { if loader == nil { panic("cannot load config from nil loader") } + loadOption := &loadOptions{} + for _, opt := range opts { + opt(loadOption) + } + values, err := loader.Load() + if err != nil { + if !loadOption.continueOnError { + return fmt.Errorf("load configuration: %w", err) + } + c.logger.Warn("failed to load configuration", "loader", loader, "error", err) + } maps.Merge(c.values, values) + // Merged to empty map to convert to lower case. providerValues := make(map[string]any) maps.Merge(providerValues, values) @@ -97,10 +109,6 @@ func (c Config) Load(loader Loader) error { values: providerValues, }) - if err != nil { - return fmt.Errorf("load configuration: %w", err) - } - return nil } diff --git a/config_test.go b/config_test.go index 14bc5558..e1c986b9 100644 --- a/config_test.go +++ b/config_test.go @@ -15,6 +15,41 @@ import ( "github.com/nil-go/konf/provider/env" ) +func TestConfig_Load_error(t *testing.T) { + t.Parallel() + + testcases := []struct { + description string + opts []konf.LoadOption + err string + }{ + { + description: "error", + err: "load configuration: load error", + }, + { + description: "continue on error", + opts: []konf.LoadOption{konf.ContinueOnError()}, + }, + } + + for _, testcase := range testcases { + testcase := testcase + + t.Run(testcase.description, func(t *testing.T) { + t.Parallel() + + config := konf.New() + err := config.Load(&errorLoader{}, testcase.opts...) + if testcase.err == "" { + assert.NoError(t, err) + } else { + assert.Equal(t, testcase.err, err.Error()) + } + }) + } +} + func TestConfig_Load_panic(t *testing.T) { t.Parallel() diff --git a/go.mod b/go.mod index f4dabb17..7f6a8c7a 100644 --- a/go.mod +++ b/go.mod @@ -3,3 +3,5 @@ module github.com/nil-go/konf go 1.21 require github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 + +retract v0.6.1 // It does not work while file is not exist diff --git a/option.go b/option.go index 5cf7daca..2a3720f6 100644 --- a/option.go +++ b/option.go @@ -56,6 +56,20 @@ type ( options Config ) +func ContinueOnError() LoadOption { + return func(options *loadOptions) { + options.continueOnError = true + } +} + +type ( + // LoadOption configures Config.Load with specific options. + LoadOption func(*loadOptions) + loadOptions struct { + continueOnError bool + } +) + // WithValueFormatter provides the value formatter for Config.Explain. // It's for hiding sensitive information (e.g. password, secret) which should not be exposed. //