From dd311b9493be5152270e1017e28e2a0a784f9446 Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Thu, 22 Aug 2024 13:28:57 +0300 Subject: [PATCH 01/10] 1. Added [EditorConfig](https://editorconfig.org/) 1. Fixed the text formatting in the README --- .editorconfig | 19 +++++++++++++++++++ .gitignore | 2 ++ README.md | 50 ++++++++++++++++++-------------------------------- 3 files changed, 39 insertions(+), 32 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..dab6d38d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +max_line_length = 120 + +[{Makefile,go.mod,go.sum,*.go}] +insert_final_newline = true +indent_size = tab +indent_style = tab +tab_width = 2 + +[*.md] +trim_trailing_whitespace = false +indent_size = tab +indent_style = space +tab_width = 2 diff --git a/.gitignore b/.gitignore index ca6a0ff8..9c2923c0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ coverage.txt bin card.png dist + +!.editorconfig diff --git a/README.md b/README.md index 6527dc14..0309001b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -

+

GoReleaser Logo -

A simple, zero-dependencies library to parse environment variables into structs.

-

+

A simple, zero-dependencies library to parse environment variables into structs.

+
###### Getting started @@ -18,8 +18,7 @@ err := env.Parse(&cfg) cfg, err := env.ParseAs[config]() ``` -You can see the full documentation and list of examples at -[pkg.go.dev](https://pkg.go.dev/github.com/caarlos0/env/v11). +You can see the full documentation and list of examples at [pkg.go.dev](https://pkg.go.dev/github.com/caarlos0/env/v11). --- @@ -27,7 +26,7 @@ You can see the full documentation and list of examples at

- encore icon + encore icon

@@ -48,19 +47,15 @@ You can see the full documentation and list of examples at - `Parse`: parse the current environment into a type - `ParseAs`: parse the current environment into a type using generics -- `ParseWithOptions`: parse the current environment into a type with custom - options -- `ParseAsithOptions`: parse the current environment into a type with custom - options and using generics +- `ParseWithOptions`: parse the current environment into a type with custom options +- `ParseAsithOptions`: parse the current environment into a type with custom options and using generics - `Must`: can be used to wrap `Parse.*` calls to panic on error - `GetFieldParams`: get the `env` parsed options for a type -- `GetFieldParamsWithOptions`: get the `env` parsed options for a type with - custom options +- `GetFieldParamsWithOptions`: get the `env` parsed options for a type with custom options ### Supported types -Out of the box all built-in types are supported, plus a few others that -are commonly used. +Out of the box all built-in types are supported, plus a few others that are commonly used. Complete list: @@ -82,8 +77,7 @@ Complete list: - `encoding.TextUnmarshaler` - `url.URL` -Pointers, slices and slices of pointers, and maps of those types are also -supported. +Pointers, slices and slices of pointers, and maps of those types are also supported. You may also add custom parsers for your types. @@ -91,15 +85,11 @@ You may also add custom parsers for your types. The following tags are provided: -- `env`: sets the environment variable name and optionally takes the tag options - described below +- `env`: sets the environment variable name and optionally takes the tag options described below - `envDefault`: sets the default value for the field -- `envPrefix`: can be used in a field that is a complex type to set a prefix to - all environment variables used in it -- `envSeparator`: sets the character to be used to separate items in slices and - maps (default: `,`) -- `envKeyValSeparator`: sets the character to be used to separate keys and their - values in maps (default: `:`) +- `envPrefix`: can be used in a field that is a complex type to set a prefix to all environment variables used in it +- `envSeparator`: sets the character to be used to separate items in slices and maps (default: `,`) +- `envKeyValSeparator`: sets the character to be used to separate keys and their values in maps (default: `:`) ### `env` tag options @@ -118,20 +108,16 @@ There are a few options available in the functions that end with `WithOptions`: - `Environment`: keys and values to be used instead of `os.Environ()` - `TagName`: specifies another tag name to use rather than the default `env` -- `RequiredIfNoDef`: set all `env` fields as required if they do not declare - `envDefault` -- `OnSet`: allows to hook into the `env` parsing and do something when a value - is set +- `RequiredIfNoDef`: set all `env` fields as required if they do not declare `envDefault` +- `OnSet`: allows to hook into the `env` parsing and do something when a value is set - `Prefix`: prefix to be used in all environment variables - `UseFieldNameByDefault`: defines whether or not `env` should use the field name by default if the `env` key is missing - `FuncMap`: custom parse functions for custom types ### Documentation and examples -Examples are live in -[pkg.go.dev](https://pkg.go.dev/github.com/caarlos0/env/v11), -and also in the -[example test file](./example_test.go). +Examples are live in [pkg.go.dev](https://pkg.go.dev/github.com/caarlos0/env/v11), +and also in the [example test file](./example_test.go). ## Badges From e748170283b1d9d83729249bc28ad9efbc561645 Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Thu, 22 Aug 2024 13:32:05 +0300 Subject: [PATCH 02/10] 1. Fixed the text formatting in the README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0309001b..cc9b489b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -

+

GoReleaser Logo

A simple, zero-dependencies library to parse environment variables into structs.

-
+

###### Getting started From 517051155a1ba8f3a6ddb2415a640d063e41533f Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Thu, 22 Aug 2024 13:34:45 +0300 Subject: [PATCH 03/10] 1. Partially rolled back text formatting edits in README - GitHub does not work correctly with formatting --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cc9b489b..c0b2a257 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -

+

GoReleaser Logo -

A simple, zero-dependencies library to parse environment variables into structs.

+

A simple, zero-dependencies library to parse environment variables into structs.

###### Getting started From 6da32f510c6f7798ebcf5b8e8393e000336e91ae Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Thu, 22 Aug 2024 14:19:12 +0300 Subject: [PATCH 04/10] Added EditorConfig linter in GitHub Actions --- .github/workflows/lint.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 90b0fe45..a26c4d1a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,8 +1,15 @@ -name: golangci-lint +name: linters on: push: pull_request: jobs: + editorconfig: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: editorconfig-checker/action-editorconfig-checker@main + - run: editorconfig-checker + golangci: name: lint runs-on: ubuntu-latest From 8ca224dc89a98ceecb9bdbd73e24b28e9bf31ffe Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Thu, 22 Aug 2024 15:31:35 +0300 Subject: [PATCH 05/10] Fixed the code based on comments from the EditorConfig linter --- .editorconfig | 14 +++++++++- .github/workflows/build.yml | 2 +- .gitignore | 2 -- env.go | 21 ++++++++++++--- env_test.go | 54 ++++++++++++++++++------------------- env_tomap_windows_test.go | 3 ++- error.go | 3 ++- go.mod | 7 +++-- 8 files changed, 68 insertions(+), 38 deletions(-) diff --git a/.editorconfig b/.editorconfig index dab6d38d..f0478a12 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,15 +5,27 @@ charset = utf-8 end_of_line = lf trim_trailing_whitespace = true max_line_length = 120 +ij_visual_guides = 100,120,150 -[{Makefile,go.mod,go.sum,*.go}] +[{go.mod,go.sum,*.go}] +insert_final_newline = true +indent_size = tab +indent_style = tab +tab_width = 2 + +[Makefile] +max_line_length = off insert_final_newline = true indent_size = tab indent_style = tab tab_width = 2 [*.md] +max_line_length = off trim_trailing_whitespace = false indent_size = tab indent_style = space tab_width = 2 + +[.mailmap] +max_line_length = off \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49d3ea8c..571a1620 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} file: ./coverage.txt - uses: goreleaser/goreleaser-action@v6 - if: success() && startsWith(github.ref, 'refs/tags/') && matrix.os == 'ubuntu-latest' && matrix.go-version == 'stable' + if: success() && startsWith(github.ref, 'refs/tags/') && matrix.os == 'ubuntu-latest' && matrix.go-version == 'stable' # editorconfig-checker-disable-line with: version: latest distribution: goreleaser-pro diff --git a/.gitignore b/.gitignore index 9c2923c0..ca6a0ff8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,3 @@ coverage.txt bin card.png dist - -!.editorconfig diff --git a/env.go b/env.go index 27776b89..e09ae6eb 100644 --- a/env.go +++ b/env.go @@ -112,7 +112,12 @@ type ParserFunc func(v string) (interface{}, error) type OnSetFn func(tag string, value interface{}, isDefault bool) // processFieldFn is a function which takes all information about a field and processes it. -type processFieldFn func(refField reflect.Value, refTypeField reflect.StructField, opts Options, fieldParams FieldParams) error +type processFieldFn func( + refField reflect.Value, + refTypeField reflect.StructField, + opts Options, + fieldParams FieldParams, +) error // Options for the parser. type Options struct { @@ -310,7 +315,12 @@ func doParse(ref reflect.Value, processField processFieldFn, opts Options) error return agrErr } -func doParseField(refField reflect.Value, refTypeField reflect.StructField, processField processFieldFn, opts Options) error { +func doParseField( + refField reflect.Value, + refTypeField reflect.StructField, + processField processFieldFn, + opts Options, +) error { if !refField.CanSet() { return nil } @@ -537,7 +547,12 @@ func parseFieldParams(field reflect.StructField, opts Options) (FieldParams, err func get(fieldParams FieldParams, opts Options) (val string, err error) { var exists, isDefault bool - val, exists, isDefault = getOr(fieldParams.Key, fieldParams.DefaultValue, fieldParams.HasDefaultValue, opts.Environment) + val, exists, isDefault = getOr( + fieldParams.Key, + fieldParams.DefaultValue, + fieldParams.HasDefaultValue, + opts.Environment, + ) if fieldParams.Expand { val = os.Expand(val, opts.getRawEnv) diff --git a/env_test.go b/env_test.go index 1a567b44..de09c272 100644 --- a/env_test.go +++ b/env_test.go @@ -408,7 +408,7 @@ func TestParsesEnv_Map(t *testing.T) { MapStringString map[string]string `env:"MAP_STRING_STRING" envSeparator:","` MapStringInt64 map[string]int64 `env:"MAP_STRING_INT64"` MapStringBool map[string]bool `env:"MAP_STRING_BOOL" envSeparator:";"` - CustomSeparatorMapStringString map[string]string `env:"CUSTOM_SEPARATOR_MAP_STRING_STRING" envSeparator:"," envKeyValSeparator:"|"` + CustomSeparatorMapStringString map[string]string `env:"CUSTOM_SEPARATOR_MAP_STRING_STRING" envSeparator:"," envKeyValSeparator:"|"` // editorconfig-checker-disable-line } mss := map[string]string{ @@ -614,7 +614,7 @@ func TestParsesEnvInnerFails(t *testing.T) { } t.Setenv("NUMBER", "not-a-number") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "Number" of type "int": strconv.ParseInt: parsing "not-a-number": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "Number" of type "int": strconv.ParseInt: parsing "not-a-number": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -630,7 +630,7 @@ func TestParsesEnvInnerFailsMultipleErrors(t *testing.T) { } t.Setenv("NUMBER", "not-a-number") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: required environment variable "NAME" is not set; parse error on field "Number" of type "int": strconv.ParseInt: parsing "not-a-number": invalid syntax; required environment variable "AGE" is not set`) + isErrorWithMessage(t, err, `env: required environment variable "NAME" is not set; parse error on field "Number" of type "int": strconv.ParseInt: parsing "not-a-number": invalid syntax; required environment variable "AGE" is not set`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) isTrue(t, errors.Is(err, EnvVarIsNotSetError{})) isTrue(t, errors.Is(err, EnvVarIsNotSetError{})) @@ -648,7 +648,7 @@ func TestParsesEnvInnerInvalid(t *testing.T) { InnerStruct: &InnerStruct{}, } err := Parse(&cfg) - isErrorWithMessage(t, err, `env: parse error on field "Number" of type "uint": strconv.ParseUint: parsing "-547": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "Number" of type "uint": strconv.ParseUint: parsing "-547": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -691,49 +691,49 @@ func TestPassReference(t *testing.T) { func TestInvalidBool(t *testing.T) { t.Setenv("BOOL", "should-be-a-bool") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Bool" of type "bool": strconv.ParseBool: parsing "should-be-a-bool": invalid syntax; parse error on field "BoolPtr" of type "*bool": strconv.ParseBool: parsing "should-be-a-bool": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "Bool" of type "bool": strconv.ParseBool: parsing "should-be-a-bool": invalid syntax; parse error on field "BoolPtr" of type "*bool": strconv.ParseBool: parsing "should-be-a-bool": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidInt(t *testing.T) { t.Setenv("INT", "should-be-an-int") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Int" of type "int": strconv.ParseInt: parsing "should-be-an-int": invalid syntax; parse error on field "IntPtr" of type "*int": strconv.ParseInt: parsing "should-be-an-int": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "Int" of type "int": strconv.ParseInt: parsing "should-be-an-int": invalid syntax; parse error on field "IntPtr" of type "*int": strconv.ParseInt: parsing "should-be-an-int": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidUint(t *testing.T) { t.Setenv("UINT", "-44") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Uint" of type "uint": strconv.ParseUint: parsing "-44": invalid syntax; parse error on field "UintPtr" of type "*uint": strconv.ParseUint: parsing "-44": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "Uint" of type "uint": strconv.ParseUint: parsing "-44": invalid syntax; parse error on field "UintPtr" of type "*uint": strconv.ParseUint: parsing "-44": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidFloat32(t *testing.T) { t.Setenv("FLOAT32", "AAA") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Float32" of type "float32": strconv.ParseFloat: parsing "AAA": invalid syntax; parse error on field "Float32Ptr" of type "*float32": strconv.ParseFloat: parsing "AAA": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "Float32" of type "float32": strconv.ParseFloat: parsing "AAA": invalid syntax; parse error on field "Float32Ptr" of type "*float32": strconv.ParseFloat: parsing "AAA": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidFloat64(t *testing.T) { t.Setenv("FLOAT64", "AAA") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Float64" of type "float64": strconv.ParseFloat: parsing "AAA": invalid syntax; parse error on field "Float64Ptr" of type "*float64": strconv.ParseFloat: parsing "AAA": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "Float64" of type "float64": strconv.ParseFloat: parsing "AAA": invalid syntax; parse error on field "Float64Ptr" of type "*float64": strconv.ParseFloat: parsing "AAA": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidUint64(t *testing.T) { t.Setenv("UINT64", "AAA") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Uint64" of type "uint64": strconv.ParseUint: parsing "AAA": invalid syntax; parse error on field "Uint64Ptr" of type "*uint64": strconv.ParseUint: parsing "AAA": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "Uint64" of type "uint64": strconv.ParseUint: parsing "AAA": invalid syntax; parse error on field "Uint64Ptr" of type "*uint64": strconv.ParseUint: parsing "AAA": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidInt64(t *testing.T) { t.Setenv("INT64", "AAA") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Int64" of type "int64": strconv.ParseInt: parsing "AAA": invalid syntax; parse error on field "Int64Ptr" of type "*int64": strconv.ParseInt: parsing "AAA": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "Int64" of type "int64": strconv.ParseInt: parsing "AAA": invalid syntax; parse error on field "Int64Ptr" of type "*int64": strconv.ParseInt: parsing "AAA": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -743,7 +743,7 @@ func TestInvalidInt64Slice(t *testing.T) { BadFloats []int64 `env:"BADINTS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]int64": strconv.ParseInt: parsing "A": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]int64": strconv.ParseInt: parsing "A": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -753,7 +753,7 @@ func TestInvalidUInt64Slice(t *testing.T) { BadFloats []uint64 `env:"BADINTS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]uint64": strconv.ParseUint: parsing "A": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]uint64": strconv.ParseUint: parsing "A": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -763,7 +763,7 @@ func TestInvalidFloat32Slice(t *testing.T) { BadFloats []float32 `env:"BADFLOATS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]float32": strconv.ParseFloat: parsing "A": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]float32": strconv.ParseFloat: parsing "A": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -773,7 +773,7 @@ func TestInvalidFloat64Slice(t *testing.T) { BadFloats []float64 `env:"BADFLOATS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]float64": strconv.ParseFloat: parsing "A": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]float64": strconv.ParseFloat: parsing "A": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -783,21 +783,21 @@ func TestInvalidBoolsSlice(t *testing.T) { BadBools []bool `env:"BADBOOLS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadBools" of type "[]bool": strconv.ParseBool: parsing "faaaalse": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "BadBools" of type "[]bool": strconv.ParseBool: parsing "faaaalse": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidDuration(t *testing.T) { t.Setenv("DURATION", "should-be-a-valid-duration") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Duration" of type "time.Duration": unable to parse duration: time: invalid duration "should-be-a-valid-duration"; parse error on field "DurationPtr" of type "*time.Duration": unable to parse duration: time: invalid duration "should-be-a-valid-duration"`) + isErrorWithMessage(t, err, `env: parse error on field "Duration" of type "time.Duration": unable to parse duration: time: invalid duration "should-be-a-valid-duration"; parse error on field "DurationPtr" of type "*time.Duration": unable to parse duration: time: invalid duration "should-be-a-valid-duration"`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidDurations(t *testing.T) { t.Setenv("DURATIONS", "1s,contains-an-invalid-duration,3s") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Durations" of type "[]time.Duration": unable to parse duration: time: invalid duration "contains-an-invalid-duration"; parse error on field "DurationPtrs" of type "[]*time.Duration": unable to parse duration: time: invalid duration "contains-an-invalid-duration"`) + isErrorWithMessage(t, err, `env: parse error on field "Durations" of type "[]time.Duration": unable to parse duration: time: invalid duration "contains-an-invalid-duration"; parse error on field "DurationPtrs" of type "[]*time.Duration": unable to parse duration: time: invalid duration "contains-an-invalid-duration"`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -813,7 +813,7 @@ func TestParseStructWithInvalidFieldKind(t *testing.T) { } t.Setenv("BLAH", "a") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "WontWorkByte" of type "uint8": strconv.ParseUint: parsing "a": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "WontWorkByte" of type "uint8": strconv.ParseUint: parsing "a": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -835,7 +835,7 @@ func TestBadSeparator(t *testing.T) { t.Setenv("WONTWORK", "1,2,3,4") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "WontWork" of type "[]int": strconv.ParseInt: parsing "1,2,3,4": invalid syntax`) + isErrorWithMessage(t, err, `env: parse error on field "WontWork" of type "[]int": strconv.ParseInt: parsing "1,2,3,4": invalid syntax`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -1320,7 +1320,7 @@ func TestTextUnmarshalerError(t *testing.T) { } t.Setenv("UNMARSHALER", "invalid") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "Unmarshaler" of type "env.unmarshaler": time: invalid duration "invalid"`) + isErrorWithMessage(t, err, `env: parse error on field "Unmarshaler" of type "env.unmarshaler": time: invalid duration "invalid"`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -1330,7 +1330,7 @@ func TestTextUnmarshalersError(t *testing.T) { } t.Setenv("UNMARSHALERS", "1s,invalid") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "Unmarshalers" of type "[]env.unmarshaler": time: invalid duration "invalid"`) + isErrorWithMessage(t, err, `env: parse error on field "Unmarshalers" of type "[]env.unmarshaler": time: invalid duration "invalid"`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -1350,7 +1350,7 @@ func TestParseInvalidURL(t *testing.T) { t.Setenv("EXAMPLE_URL_2", "nope://s s/") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "ExampleURL" of type "url.URL": unable to parse URL: parse "nope://s s/": invalid character " " in host name`) + isErrorWithMessage(t, err, `env: parse error on field "ExampleURL" of type "url.URL": unable to parse URL: parse "nope://s s/": invalid character " " in host name`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, ParseError{})) } @@ -1452,7 +1452,7 @@ func TestFileBadFile(t *testing.T) { } err := Parse(&config{}) - isErrorWithMessage(t, err, fmt.Sprintf(`env: could not load content of file "%s" from variable SECRET_KEY: open %s: %s`, filename, filename, oserr)) + isErrorWithMessage(t, err, fmt.Sprintf(`env: could not load content of file "%s" from variable SECRET_KEY: open %s: %s`, filename, filename, oserr)) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, LoadFileContentError{})) } @@ -1524,7 +1524,7 @@ func TestRequiredIfNoDefOption(t *testing.T) { t.Run("missing", func(t *testing.T) { err := ParseWithOptions(&cfg, Options{RequiredIfNoDef: true}) - isErrorWithMessage(t, err, `env: required environment variable "NAME" is not set; required environment variable "FRUIT" is not set`) + isErrorWithMessage(t, err, `env: required environment variable "NAME" is not set; required environment variable "FRUIT" is not set`) // editorconfig-checker-disable-line isTrue(t, errors.Is(err, EnvVarIsNotSetError{})) t.Setenv("NAME", "John") err = ParseWithOptions(&cfg, Options{RequiredIfNoDef: true}) @@ -1584,7 +1584,7 @@ func TestPrefix(t *testing.T) { Clean Config } cfg := ComplexConfig{} - isNoErr(t, ParseWithOptions(&cfg, Options{Environment: map[string]string{"FOO_HOME": "/foo", "BAR_HOME": "/bar", "HOME": "/clean"}})) + isNoErr(t, ParseWithOptions(&cfg, Options{Environment: map[string]string{"FOO_HOME": "/foo", "BAR_HOME": "/bar", "HOME": "/clean"}})) // editorconfig-checker-disable-line isEqual(t, "/foo", cfg.Foo.Home) isEqual(t, "/bar", cfg.Bar.Home) isEqual(t, "/clean", cfg.Clean.Home) @@ -1605,7 +1605,7 @@ func TestPrefixPointers(t *testing.T) { Bar: &Test{}, Clean: &Test{}, } - isNoErr(t, ParseWithOptions(&cfg, Options{Environment: map[string]string{"FOO_TEST": "kek", "BAR_TEST": "lel", "TEST": "clean"}})) + isNoErr(t, ParseWithOptions(&cfg, Options{Environment: map[string]string{"FOO_TEST": "kek", "BAR_TEST": "lel", "TEST": "clean"}})) // editorconfig-checker-disable-line isEqual(t, "kek", cfg.Foo.Str) isEqual(t, "lel", cfg.Bar.Str) isEqual(t, "clean", cfg.Clean.Str) diff --git a/env_tomap_windows_test.go b/env_tomap_windows_test.go index dc1458b3..d8efdc64 100644 --- a/env_tomap_windows_test.go +++ b/env_tomap_windows_test.go @@ -4,7 +4,8 @@ package env import "testing" -// On Windows, environment variables can start with '='. This test verifies this behavior without relying on a Windows environment. +// On Windows, environment variables can start with '='. +// This test verifies this behavior without relying on a Windows environment. // See env_windows.go in the Go source: https://github.com/golang/go/blob/master/src/syscall/env_windows.go#L58 func TestToMapWindows(t *testing.T) { envVars := []string{"=::=::\\", "=C:=C:\\test", "VAR=REGULARVAR", "FOO=", "BAR"} diff --git a/error.go b/error.go index 156ca3ec..b14857f1 100644 --- a/error.go +++ b/error.go @@ -6,7 +6,8 @@ import ( "strings" ) -// An aggregated error wrapper to combine gathered errors. This allows either to display all errors or convert them individually +// An aggregated error wrapper to combine gathered errors. +// This allows either to display all errors or convert them individually // List of the available errors // ParseError // NotStructPtrError diff --git a/go.mod b/go.mod index affcbd49..92cabd79 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,10 @@ module github.com/caarlos0/env/v11 -retract v11.0.1 // v11.0.1 accidentally introduced a breaking change regarding the behavior of nil pointers. You can now chose to auto-initialize them by setting the `init` tag option. +// v11.0.1 accidentally introduced a breaking change regarding the behavior of nil pointers. +// You can now chose to auto-initialize them by setting the `init` tag option. +retract v11.0.1 -retract v11.2.0 // v11.2.0 accidentally introduced a breaking change regarding the behavior of nil slices of complex types. +// v11.2.0 accidentally introduced a breaking change regarding the behavior of nil slices of complex types. +retract v11.2.0 go 1.18 From 9bc8f424c5afb25f5f87a129375e5672e181afb5 Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Thu, 22 Aug 2024 19:46:40 +0300 Subject: [PATCH 06/10] Replaced the linter and corrected the comments from the new linter --- .github/workflows/build.yml | 2 +- .github/workflows/lint.yml | 9 +----- .golangci.yml | 14 +++++++++ env_test.go | 62 ++++++++++++++++++------------------- error.go | 2 +- 5 files changed, 48 insertions(+), 41 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 571a1620..49d3ea8c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} file: ./coverage.txt - uses: goreleaser/goreleaser-action@v6 - if: success() && startsWith(github.ref, 'refs/tags/') && matrix.os == 'ubuntu-latest' && matrix.go-version == 'stable' # editorconfig-checker-disable-line + if: success() && startsWith(github.ref, 'refs/tags/') && matrix.os == 'ubuntu-latest' && matrix.go-version == 'stable' with: version: latest distribution: goreleaser-pro diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a26c4d1a..90b0fe45 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,15 +1,8 @@ -name: linters +name: golangci-lint on: push: pull_request: jobs: - editorconfig: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: editorconfig-checker/action-editorconfig-checker@main - - run: editorconfig-checker - golangci: name: lint runs-on: ubuntu-latest diff --git a/.golangci.yml b/.golangci.yml index ff791f86..73db6131 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,16 @@ +linters-settings: + revive: + rules: + - name: line-length-limit + arguments: [120] + +issues: + exclude-rules: + - path: _test\.go + linters: + - revive + text: "line-length-limit:" + linters: enable: - thelper @@ -6,3 +19,4 @@ linters: - unconvert - unparam - wastedassign + - revive diff --git a/env_test.go b/env_test.go index de09c272..1d90b952 100644 --- a/env_test.go +++ b/env_test.go @@ -408,7 +408,7 @@ func TestParsesEnv_Map(t *testing.T) { MapStringString map[string]string `env:"MAP_STRING_STRING" envSeparator:","` MapStringInt64 map[string]int64 `env:"MAP_STRING_INT64"` MapStringBool map[string]bool `env:"MAP_STRING_BOOL" envSeparator:";"` - CustomSeparatorMapStringString map[string]string `env:"CUSTOM_SEPARATOR_MAP_STRING_STRING" envSeparator:"," envKeyValSeparator:"|"` // editorconfig-checker-disable-line + CustomSeparatorMapStringString map[string]string `env:"CUSTOM_SEPARATOR_MAP_STRING_STRING" envSeparator:"," envKeyValSeparator:"|"` } mss := map[string]string{ @@ -467,7 +467,7 @@ func TestParseCustomMapType(t *testing.T) { var cfg config isNoErr(t, ParseWithOptions(&cfg, Options{FuncMap: map[reflect.Type]ParserFunc{ - reflect.TypeOf(custommap{}): func(value string) (interface{}, error) { + reflect.TypeOf(custommap{}): func(_ string) (interface{}, error) { return custommap(map[string]bool{}), nil }, }})) @@ -529,7 +529,7 @@ func TestParseMapCustomKeyTypeError(t *testing.T) { var cfg config err := ParseWithOptions(&cfg, Options{FuncMap: map[reflect.Type]ParserFunc{ - reflect.TypeOf(CustomKey("")): func(value string) (interface{}, error) { + reflect.TypeOf(CustomKey("")): func(_ string) (interface{}, error) { return nil, fmt.Errorf("custom error") }, }}) @@ -547,7 +547,7 @@ func TestParseMapCustomValueTypeError(t *testing.T) { var cfg config err := ParseWithOptions(&cfg, Options{FuncMap: map[reflect.Type]ParserFunc{ - reflect.TypeOf(Customval("")): func(value string) (interface{}, error) { + reflect.TypeOf(Customval("")): func(_ string) (interface{}, error) { return nil, fmt.Errorf("custom error") }, }}) @@ -614,7 +614,7 @@ func TestParsesEnvInnerFails(t *testing.T) { } t.Setenv("NUMBER", "not-a-number") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "Number" of type "int": strconv.ParseInt: parsing "not-a-number": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Number" of type "int": strconv.ParseInt: parsing "not-a-number": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } @@ -630,7 +630,7 @@ func TestParsesEnvInnerFailsMultipleErrors(t *testing.T) { } t.Setenv("NUMBER", "not-a-number") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: required environment variable "NAME" is not set; parse error on field "Number" of type "int": strconv.ParseInt: parsing "not-a-number": invalid syntax; required environment variable "AGE" is not set`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: required environment variable "NAME" is not set; parse error on field "Number" of type "int": strconv.ParseInt: parsing "not-a-number": invalid syntax; required environment variable "AGE" is not set`) isTrue(t, errors.Is(err, ParseError{})) isTrue(t, errors.Is(err, EnvVarIsNotSetError{})) isTrue(t, errors.Is(err, EnvVarIsNotSetError{})) @@ -648,7 +648,7 @@ func TestParsesEnvInnerInvalid(t *testing.T) { InnerStruct: &InnerStruct{}, } err := Parse(&cfg) - isErrorWithMessage(t, err, `env: parse error on field "Number" of type "uint": strconv.ParseUint: parsing "-547": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Number" of type "uint": strconv.ParseUint: parsing "-547": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } @@ -691,49 +691,49 @@ func TestPassReference(t *testing.T) { func TestInvalidBool(t *testing.T) { t.Setenv("BOOL", "should-be-a-bool") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Bool" of type "bool": strconv.ParseBool: parsing "should-be-a-bool": invalid syntax; parse error on field "BoolPtr" of type "*bool": strconv.ParseBool: parsing "should-be-a-bool": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Bool" of type "bool": strconv.ParseBool: parsing "should-be-a-bool": invalid syntax; parse error on field "BoolPtr" of type "*bool": strconv.ParseBool: parsing "should-be-a-bool": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidInt(t *testing.T) { t.Setenv("INT", "should-be-an-int") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Int" of type "int": strconv.ParseInt: parsing "should-be-an-int": invalid syntax; parse error on field "IntPtr" of type "*int": strconv.ParseInt: parsing "should-be-an-int": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Int" of type "int": strconv.ParseInt: parsing "should-be-an-int": invalid syntax; parse error on field "IntPtr" of type "*int": strconv.ParseInt: parsing "should-be-an-int": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidUint(t *testing.T) { t.Setenv("UINT", "-44") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Uint" of type "uint": strconv.ParseUint: parsing "-44": invalid syntax; parse error on field "UintPtr" of type "*uint": strconv.ParseUint: parsing "-44": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Uint" of type "uint": strconv.ParseUint: parsing "-44": invalid syntax; parse error on field "UintPtr" of type "*uint": strconv.ParseUint: parsing "-44": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidFloat32(t *testing.T) { t.Setenv("FLOAT32", "AAA") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Float32" of type "float32": strconv.ParseFloat: parsing "AAA": invalid syntax; parse error on field "Float32Ptr" of type "*float32": strconv.ParseFloat: parsing "AAA": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Float32" of type "float32": strconv.ParseFloat: parsing "AAA": invalid syntax; parse error on field "Float32Ptr" of type "*float32": strconv.ParseFloat: parsing "AAA": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidFloat64(t *testing.T) { t.Setenv("FLOAT64", "AAA") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Float64" of type "float64": strconv.ParseFloat: parsing "AAA": invalid syntax; parse error on field "Float64Ptr" of type "*float64": strconv.ParseFloat: parsing "AAA": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Float64" of type "float64": strconv.ParseFloat: parsing "AAA": invalid syntax; parse error on field "Float64Ptr" of type "*float64": strconv.ParseFloat: parsing "AAA": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidUint64(t *testing.T) { t.Setenv("UINT64", "AAA") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Uint64" of type "uint64": strconv.ParseUint: parsing "AAA": invalid syntax; parse error on field "Uint64Ptr" of type "*uint64": strconv.ParseUint: parsing "AAA": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Uint64" of type "uint64": strconv.ParseUint: parsing "AAA": invalid syntax; parse error on field "Uint64Ptr" of type "*uint64": strconv.ParseUint: parsing "AAA": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidInt64(t *testing.T) { t.Setenv("INT64", "AAA") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Int64" of type "int64": strconv.ParseInt: parsing "AAA": invalid syntax; parse error on field "Int64Ptr" of type "*int64": strconv.ParseInt: parsing "AAA": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Int64" of type "int64": strconv.ParseInt: parsing "AAA": invalid syntax; parse error on field "Int64Ptr" of type "*int64": strconv.ParseInt: parsing "AAA": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } @@ -743,7 +743,7 @@ func TestInvalidInt64Slice(t *testing.T) { BadFloats []int64 `env:"BADINTS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]int64": strconv.ParseInt: parsing "A": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]int64": strconv.ParseInt: parsing "A": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } @@ -753,7 +753,7 @@ func TestInvalidUInt64Slice(t *testing.T) { BadFloats []uint64 `env:"BADINTS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]uint64": strconv.ParseUint: parsing "A": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]uint64": strconv.ParseUint: parsing "A": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } @@ -763,7 +763,7 @@ func TestInvalidFloat32Slice(t *testing.T) { BadFloats []float32 `env:"BADFLOATS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]float32": strconv.ParseFloat: parsing "A": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]float32": strconv.ParseFloat: parsing "A": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } @@ -773,7 +773,7 @@ func TestInvalidFloat64Slice(t *testing.T) { BadFloats []float64 `env:"BADFLOATS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]float64": strconv.ParseFloat: parsing "A": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "BadFloats" of type "[]float64": strconv.ParseFloat: parsing "A": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } @@ -783,21 +783,21 @@ func TestInvalidBoolsSlice(t *testing.T) { BadBools []bool `env:"BADBOOLS"` } err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "BadBools" of type "[]bool": strconv.ParseBool: parsing "faaaalse": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "BadBools" of type "[]bool": strconv.ParseBool: parsing "faaaalse": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidDuration(t *testing.T) { t.Setenv("DURATION", "should-be-a-valid-duration") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Duration" of type "time.Duration": unable to parse duration: time: invalid duration "should-be-a-valid-duration"; parse error on field "DurationPtr" of type "*time.Duration": unable to parse duration: time: invalid duration "should-be-a-valid-duration"`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Duration" of type "time.Duration": unable to parse duration: time: invalid duration "should-be-a-valid-duration"; parse error on field "DurationPtr" of type "*time.Duration": unable to parse duration: time: invalid duration "should-be-a-valid-duration"`) isTrue(t, errors.Is(err, ParseError{})) } func TestInvalidDurations(t *testing.T) { t.Setenv("DURATIONS", "1s,contains-an-invalid-duration,3s") err := Parse(&Config{}) - isErrorWithMessage(t, err, `env: parse error on field "Durations" of type "[]time.Duration": unable to parse duration: time: invalid duration "contains-an-invalid-duration"; parse error on field "DurationPtrs" of type "[]*time.Duration": unable to parse duration: time: invalid duration "contains-an-invalid-duration"`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Durations" of type "[]time.Duration": unable to parse duration: time: invalid duration "contains-an-invalid-duration"; parse error on field "DurationPtrs" of type "[]*time.Duration": unable to parse duration: time: invalid duration "contains-an-invalid-duration"`) isTrue(t, errors.Is(err, ParseError{})) } @@ -813,7 +813,7 @@ func TestParseStructWithInvalidFieldKind(t *testing.T) { } t.Setenv("BLAH", "a") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "WontWorkByte" of type "uint8": strconv.ParseUint: parsing "a": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "WontWorkByte" of type "uint8": strconv.ParseUint: parsing "a": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } @@ -835,7 +835,7 @@ func TestBadSeparator(t *testing.T) { t.Setenv("WONTWORK", "1,2,3,4") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "WontWork" of type "[]int": strconv.ParseInt: parsing "1,2,3,4": invalid syntax`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "WontWork" of type "[]int": strconv.ParseInt: parsing "1,2,3,4": invalid syntax`) isTrue(t, errors.Is(err, ParseError{})) } @@ -1116,7 +1116,7 @@ func TestCustomParserError(t *testing.T) { name string } - customParserFunc := func(v string) (interface{}, error) { + customParserFunc := func(_ string) (interface{}, error) { return nil, errors.New("something broke") } @@ -1320,7 +1320,7 @@ func TestTextUnmarshalerError(t *testing.T) { } t.Setenv("UNMARSHALER", "invalid") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "Unmarshaler" of type "env.unmarshaler": time: invalid duration "invalid"`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Unmarshaler" of type "env.unmarshaler": time: invalid duration "invalid"`) isTrue(t, errors.Is(err, ParseError{})) } @@ -1330,7 +1330,7 @@ func TestTextUnmarshalersError(t *testing.T) { } t.Setenv("UNMARSHALERS", "1s,invalid") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "Unmarshalers" of type "[]env.unmarshaler": time: invalid duration "invalid"`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "Unmarshalers" of type "[]env.unmarshaler": time: invalid duration "invalid"`) isTrue(t, errors.Is(err, ParseError{})) } @@ -1350,7 +1350,7 @@ func TestParseInvalidURL(t *testing.T) { t.Setenv("EXAMPLE_URL_2", "nope://s s/") err := Parse(&config{}) - isErrorWithMessage(t, err, `env: parse error on field "ExampleURL" of type "url.URL": unable to parse URL: parse "nope://s s/": invalid character " " in host name`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: parse error on field "ExampleURL" of type "url.URL": unable to parse URL: parse "nope://s s/": invalid character " " in host name`) isTrue(t, errors.Is(err, ParseError{})) } @@ -1452,7 +1452,7 @@ func TestFileBadFile(t *testing.T) { } err := Parse(&config{}) - isErrorWithMessage(t, err, fmt.Sprintf(`env: could not load content of file "%s" from variable SECRET_KEY: open %s: %s`, filename, filename, oserr)) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, fmt.Sprintf(`env: could not load content of file "%s" from variable SECRET_KEY: open %s: %s`, filename, filename, oserr)) isTrue(t, errors.Is(err, LoadFileContentError{})) } @@ -1524,7 +1524,7 @@ func TestRequiredIfNoDefOption(t *testing.T) { t.Run("missing", func(t *testing.T) { err := ParseWithOptions(&cfg, Options{RequiredIfNoDef: true}) - isErrorWithMessage(t, err, `env: required environment variable "NAME" is not set; required environment variable "FRUIT" is not set`) // editorconfig-checker-disable-line + isErrorWithMessage(t, err, `env: required environment variable "NAME" is not set; required environment variable "FRUIT" is not set`) isTrue(t, errors.Is(err, EnvVarIsNotSetError{})) t.Setenv("NAME", "John") err = ParseWithOptions(&cfg, Options{RequiredIfNoDef: true}) @@ -1584,7 +1584,7 @@ func TestPrefix(t *testing.T) { Clean Config } cfg := ComplexConfig{} - isNoErr(t, ParseWithOptions(&cfg, Options{Environment: map[string]string{"FOO_HOME": "/foo", "BAR_HOME": "/bar", "HOME": "/clean"}})) // editorconfig-checker-disable-line + isNoErr(t, ParseWithOptions(&cfg, Options{Environment: map[string]string{"FOO_HOME": "/foo", "BAR_HOME": "/bar", "HOME": "/clean"}})) isEqual(t, "/foo", cfg.Foo.Home) isEqual(t, "/bar", cfg.Bar.Home) isEqual(t, "/clean", cfg.Clean.Home) @@ -1605,7 +1605,7 @@ func TestPrefixPointers(t *testing.T) { Bar: &Test{}, Clean: &Test{}, } - isNoErr(t, ParseWithOptions(&cfg, Options{Environment: map[string]string{"FOO_TEST": "kek", "BAR_TEST": "lel", "TEST": "clean"}})) // editorconfig-checker-disable-line + isNoErr(t, ParseWithOptions(&cfg, Options{Environment: map[string]string{"FOO_TEST": "kek", "BAR_TEST": "lel", "TEST": "clean"}})) isEqual(t, "kek", cfg.Foo.Str) isEqual(t, "lel", cfg.Bar.Str) isEqual(t, "clean", cfg.Clean.Str) diff --git a/error.go b/error.go index b14857f1..8cec505e 100644 --- a/error.go +++ b/error.go @@ -106,7 +106,7 @@ func (e NoSupportedTagOptionError) Error() string { // This error occurs when the required variable is not set // Read about required fields: https://github.com/caarlos0/env#required-fields -type EnvVarIsNotSetError struct { +type EnvVarIsNotSetError struct { //nolint:revive // FIXME https://github.com/caarlos0/env/issues/328 Key string } From 1743abf14f4a072ae638c8aaecb684a8b35c46f6 Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Thu, 22 Aug 2024 20:31:16 +0300 Subject: [PATCH 07/10] Revert EditorConfig linter --- .github/workflows/build.yml | 2 +- .github/workflows/lint.yml | 9 ++++++++- env_test.go | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49d3ea8c..571a1620 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} file: ./coverage.txt - uses: goreleaser/goreleaser-action@v6 - if: success() && startsWith(github.ref, 'refs/tags/') && matrix.os == 'ubuntu-latest' && matrix.go-version == 'stable' + if: success() && startsWith(github.ref, 'refs/tags/') && matrix.os == 'ubuntu-latest' && matrix.go-version == 'stable' # editorconfig-checker-disable-line with: version: latest distribution: goreleaser-pro diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 90b0fe45..a26c4d1a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,8 +1,15 @@ -name: golangci-lint +name: linters on: push: pull_request: jobs: + editorconfig: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: editorconfig-checker/action-editorconfig-checker@main + - run: editorconfig-checker + golangci: name: lint runs-on: ubuntu-latest diff --git a/env_test.go b/env_test.go index 1d90b952..8784be39 100644 --- a/env_test.go +++ b/env_test.go @@ -1,3 +1,4 @@ +// editorconfig-checker-disable-file package env import ( From b55e8c75dc0ee10c4e16e8683d8de4026dcce3ec Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Thu, 22 Aug 2024 21:47:44 +0300 Subject: [PATCH 08/10] Fixer review comments --- .editorconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index f0478a12..f03fc66f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,7 +5,9 @@ charset = utf-8 end_of_line = lf trim_trailing_whitespace = true max_line_length = 120 -ij_visual_guides = 100,120,150 +# visual setting for intelliJ IDE, no consequences on code validation +# https://www.jetbrains.com/help/idea/editorconfig.html +ij_visual_guides = 100, 120, 150 [{go.mod,go.sum,*.go}] insert_final_newline = true From 901bdff9869f5349be8459981900468d10496b20 Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Sat, 24 Aug 2024 23:14:45 +0300 Subject: [PATCH 09/10] Fixed review comments --- .editorconfig | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.editorconfig b/.editorconfig index f03fc66f..679ee238 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,26 +1,21 @@ -root = true - [*] charset = utf-8 end_of_line = lf trim_trailing_whitespace = true max_line_length = 120 -# visual setting for intelliJ IDE, no consequences on code validation -# https://www.jetbrains.com/help/idea/editorconfig.html -ij_visual_guides = 100, 120, 150 [{go.mod,go.sum,*.go}] insert_final_newline = true indent_size = tab indent_style = tab -tab_width = 2 +tab_width = 4 [Makefile] max_line_length = off insert_final_newline = true indent_size = tab indent_style = tab -tab_width = 2 +tab_width = 4 [*.md] max_line_length = off From 84a2f9b1c546c3bf46c5a08cced5d08449b4b5ca Mon Sep 17 00:00:00 2001 From: Viktor Alenkov Date: Sat, 24 Aug 2024 23:15:47 +0300 Subject: [PATCH 10/10] Fixed review comments --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 679ee238..0d3bd399 100644 --- a/.editorconfig +++ b/.editorconfig @@ -25,4 +25,4 @@ indent_style = space tab_width = 2 [.mailmap] -max_line_length = off \ No newline at end of file +max_line_length = off