Добавлена функция вывода описания конфигурации в markdown.
All checks were successful
test / test (push) Successful in 26s
All checks were successful
test / test (push) Successful in 26s
This commit is contained in:
parent
192724f3b8
commit
ce2ec715be
@ -19,15 +19,8 @@ jobs:
|
||||
|
||||
- name: set-up dependencies
|
||||
run: |
|
||||
go install github.com/kisielk/errcheck@latest
|
||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
go install github.com/sashamelentyev/usestdlibvars@latest
|
||||
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest
|
||||
make vendor
|
||||
|
||||
- name: lint
|
||||
run: make lint
|
||||
|
||||
- name: golangci-lint
|
||||
uses: https://github.com/golangci/golangci-lint-action@v7
|
||||
with:
|
||||
|
@ -1,10 +1,24 @@
|
||||
version: "0.2"
|
||||
ignorePaths: []
|
||||
dictionaryDefinitions: []
|
||||
dictionaries: []
|
||||
dictionaryDefinitions:
|
||||
- name: custom-dictionary
|
||||
path: ./.cspell/custom-dictionary.txt
|
||||
addWords: true
|
||||
dictionaries:
|
||||
- custom-dictionary
|
||||
words: []
|
||||
ignoreWords:
|
||||
- GOCMD
|
||||
- GOPATH
|
||||
- GOTEST
|
||||
- GOVET
|
||||
- Txterm
|
||||
- covermode
|
||||
- coverprofile
|
||||
- davecgh
|
||||
- difflib
|
||||
- gocov
|
||||
- pmezard
|
||||
- setaf
|
||||
- tput
|
||||
import: []
|
||||
|
72
env.go
72
env.go
@ -27,13 +27,16 @@ import (
|
||||
// ParseValueEnvFunc func to parse env value
|
||||
type ParseValueEnvFunc func(value reflect.Value, prefix string) error
|
||||
|
||||
// ParseFieldEnvFunc func to parse env field
|
||||
type ParseFieldEnvFunc func(out io.Writer, field reflect.StructField, prefix string) error
|
||||
|
||||
// Parse parses given structure interface, extracts environment definitions
|
||||
// from its tag and sets structure with defined environment variables
|
||||
func ParseEnv(out interface{}) error {
|
||||
return ParseEnvWith(out, "", parseValueEnv)
|
||||
}
|
||||
|
||||
// UsageEnv prints usage description of config i to out
|
||||
// UsageEnv prints usage description of config in to out in text
|
||||
func UsageEnv(out io.Writer, in interface{}) error {
|
||||
if _, err := out.Write([]byte("Environment Usage:\n")); err != nil {
|
||||
return fmt.Errorf("write usage: %w", err)
|
||||
@ -42,7 +45,7 @@ func UsageEnv(out io.Writer, in interface{}) error {
|
||||
buf := bytes.NewBufferString("")
|
||||
|
||||
if err := ParseEnvWith(in, "", func(value reflect.Value, prefix string) error {
|
||||
return usageValueEnv(buf, value, prefix)
|
||||
return usageValueEnv(buf, value, prefix, usageFieldEnv)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -72,6 +75,21 @@ func UsageEnv(out io.Writer, in interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarkdownEnv prints description of config in to out in markdown
|
||||
func MarkdownEnv(out io.Writer, in interface{}) error {
|
||||
msg := "# Environment variables\n\n"
|
||||
msg += "| Name | Default | Required | Usage |\n"
|
||||
msg += "| :--- | :------ | :------: | :---- |\n"
|
||||
|
||||
if _, err := out.Write([]byte(msg)); err != nil {
|
||||
return fmt.Errorf("write markdown: %w", err)
|
||||
}
|
||||
|
||||
return ParseEnvWith(in, "", func(value reflect.Value, prefix string) error {
|
||||
return usageValueEnv(out, value, prefix, markdownFieldEnv)
|
||||
})
|
||||
}
|
||||
|
||||
// ParseWith parses with given structure interface and environment name prefix
|
||||
// It is normally used in nested structure.
|
||||
// For example: we have such structure
|
||||
@ -103,7 +121,9 @@ func ParseEnvWith(out interface{}, prefix string, parser ParseValueEnvFunc) erro
|
||||
return parser(valueOfStruct, prefix)
|
||||
}
|
||||
|
||||
func usageValueEnv(out io.Writer, value reflect.Value, prefix string) error {
|
||||
func usageValueEnv(
|
||||
out io.Writer, value reflect.Value, prefix string, usageField ParseFieldEnvFunc,
|
||||
) error {
|
||||
var err error
|
||||
|
||||
typeOfStruct := value.Type()
|
||||
@ -120,22 +140,18 @@ func usageValueEnv(out io.Writer, value reflect.Value, prefix string) error {
|
||||
valueOfField.Interface(),
|
||||
prefix+structOfField.Tag.Get("env"),
|
||||
func(value reflect.Value, prefix string) error {
|
||||
return usageValueEnv(out, value, prefix)
|
||||
return usageValueEnv(out, value, prefix, usageField)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else if kindOfField == reflect.Struct {
|
||||
err = usageValueEnv(out, valueOfField, prefix+structOfField.Tag.Get("env"))
|
||||
err = usageValueEnv(out, valueOfField, prefix+structOfField.Tag.Get("env"), usageField)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if kindOfField != reflect.Struct {
|
||||
err = usageFieldValueEnv(out, structOfField, prefix)
|
||||
if err == nil && kindOfField != reflect.Struct {
|
||||
err = usageField(out, structOfField, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,7 +272,7 @@ func setSimpleEnvValue(value reflect.Value, field reflect.StructField, str strin
|
||||
return err
|
||||
}
|
||||
|
||||
func usageFieldValueEnv(out io.Writer, field reflect.StructField, prefix string) error {
|
||||
func usageFieldEnv(out io.Writer, field reflect.StructField, prefix string) error {
|
||||
envName := field.Tag.Get("env")
|
||||
if envName == "" {
|
||||
return nil
|
||||
@ -267,6 +283,8 @@ func usageFieldValueEnv(out io.Writer, field reflect.StructField, prefix string)
|
||||
|
||||
if def := field.Tag.Get("default"); def != "" {
|
||||
msg += " (default: " + def + ")"
|
||||
} else if req := field.Tag.Get("required"); req == "true" {
|
||||
msg += " (required)"
|
||||
}
|
||||
|
||||
if _, err := out.Write([]byte(msg + "\n")); err != nil {
|
||||
@ -275,3 +293,33 @@ func usageFieldValueEnv(out io.Writer, field reflect.StructField, prefix string)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func markdownFieldEnv(out io.Writer, field reflect.StructField, prefix string) error {
|
||||
const mark = "✅"
|
||||
|
||||
envName := field.Tag.Get("env")
|
||||
if envName == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
envName = prefix + envName
|
||||
msg := "| " + envName + " | "
|
||||
|
||||
if def := field.Tag.Get("default"); def != "" {
|
||||
msg += def
|
||||
}
|
||||
|
||||
msg += " | "
|
||||
|
||||
if req := field.Tag.Get("required"); req == "true" {
|
||||
msg += mark
|
||||
}
|
||||
|
||||
msg += " | " + strings.ReplaceAll(field.Tag.Get("usage"), "|", "|") + " |\n"
|
||||
|
||||
if _, err := out.Write([]byte(msg)); err != nil {
|
||||
return fmt.Errorf("write markdown: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -147,6 +147,11 @@ func TestEnvUsage(t *testing.T) {
|
||||
assert.NoError(t, UsageEnv(os.Stdout, &conf))
|
||||
}
|
||||
|
||||
func TestEnvMarkdown(t *testing.T) {
|
||||
conf := test.ServiceConfig{}
|
||||
assert.NoError(t, MarkdownEnv(os.Stdout, &conf))
|
||||
}
|
||||
|
||||
func TestServiceLoginConfigEnv(t *testing.T) {
|
||||
var err error
|
||||
|
||||
|
12
makefile
12
makefile
@ -82,11 +82,8 @@ endif
|
||||
## Lint
|
||||
|
||||
lint: ## Run all available linters.
|
||||
go vet ./...
|
||||
errcheck ./...
|
||||
staticcheck ./...
|
||||
# usestdlibvars ./...
|
||||
shadow ./...
|
||||
@golangci-lint version
|
||||
@golangci-lint run
|
||||
@$(ECHO_CMD) "Lint\t\t${GREEN}[OK]${RESET}"
|
||||
.PHONY:lint
|
||||
|
||||
@ -97,11 +94,6 @@ golangci-lint-install: ## Install golangci-lint util
|
||||
curl -sfL ${GOLANGCI_URL} | sh -s -- -b ${GOPATH}/bin ${GOLANGCI_VERSION}
|
||||
.PHONY:lint-golangci-install
|
||||
|
||||
golangci-lint: ## Run golangci-lint linter
|
||||
@golangci-lint run
|
||||
@$(ECHO_CMD) "GolangCI Lint\t${GREEN}[OK]${RESET}"
|
||||
.PHONY:golangci-lint
|
||||
|
||||
## Help
|
||||
|
||||
help: ## Show this help.
|
||||
|
@ -39,8 +39,8 @@ type LogConfig struct {
|
||||
}
|
||||
|
||||
type ServiceConfig struct {
|
||||
Host string `cli:"hostname" env:"CONFIG_TEST_SERVICE_HOST" usage:"service hostname"`
|
||||
Port int `cli:"port" env:"CONFIG_TEST_SERVICE_PORT" usage:"service port"`
|
||||
Host string `cli:"hostname" env:"CONFIG_TEST_SERVICE_HOST" required:"true" usage:"service hostname"`
|
||||
Port int `cli:"port" env:"CONFIG_TEST_SERVICE_PORT" required:"true" usage:"service port"`
|
||||
DBConfig DBConfig `cli:"database" env:"CONFIG_TEST_SERVICE_DB_" usage:"database configuration"`
|
||||
Login *LoginConfig `cli:"login" env:"CONFIG_TEST_SERVICE_LOGIN_" usage:"login user and password"`
|
||||
Log LogConfig `cli:"log" env:"CONFIG_TEST_SERVICE_LOG_" usage:"service log configuration"`
|
||||
|
Loading…
x
Reference in New Issue
Block a user