Добавлена функция вывода описания конфигурации в 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
|
- name: set-up dependencies
|
||||||
run: |
|
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
|
make vendor
|
||||||
|
|
||||||
- name: lint
|
|
||||||
run: make lint
|
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: https://github.com/golangci/golangci-lint-action@v7
|
uses: https://github.com/golangci/golangci-lint-action@v7
|
||||||
with:
|
with:
|
||||||
|
@ -1,10 +1,24 @@
|
|||||||
version: "0.2"
|
version: "0.2"
|
||||||
ignorePaths: []
|
ignorePaths: []
|
||||||
dictionaryDefinitions: []
|
dictionaryDefinitions:
|
||||||
dictionaries: []
|
- name: custom-dictionary
|
||||||
|
path: ./.cspell/custom-dictionary.txt
|
||||||
|
addWords: true
|
||||||
|
dictionaries:
|
||||||
|
- custom-dictionary
|
||||||
words: []
|
words: []
|
||||||
ignoreWords:
|
ignoreWords:
|
||||||
|
- GOCMD
|
||||||
|
- GOPATH
|
||||||
|
- GOTEST
|
||||||
|
- GOVET
|
||||||
|
- Txterm
|
||||||
|
- covermode
|
||||||
|
- coverprofile
|
||||||
- davecgh
|
- davecgh
|
||||||
- difflib
|
- difflib
|
||||||
|
- gocov
|
||||||
- pmezard
|
- pmezard
|
||||||
|
- setaf
|
||||||
|
- tput
|
||||||
import: []
|
import: []
|
||||||
|
72
env.go
72
env.go
@ -27,13 +27,16 @@ import (
|
|||||||
// ParseValueEnvFunc func to parse env value
|
// ParseValueEnvFunc func to parse env value
|
||||||
type ParseValueEnvFunc func(value reflect.Value, prefix string) error
|
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
|
// Parse parses given structure interface, extracts environment definitions
|
||||||
// from its tag and sets structure with defined environment variables
|
// from its tag and sets structure with defined environment variables
|
||||||
func ParseEnv(out interface{}) error {
|
func ParseEnv(out interface{}) error {
|
||||||
return ParseEnvWith(out, "", parseValueEnv)
|
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 {
|
func UsageEnv(out io.Writer, in interface{}) error {
|
||||||
if _, err := out.Write([]byte("Environment Usage:\n")); err != nil {
|
if _, err := out.Write([]byte("Environment Usage:\n")); err != nil {
|
||||||
return fmt.Errorf("write usage: %w", err)
|
return fmt.Errorf("write usage: %w", err)
|
||||||
@ -42,7 +45,7 @@ func UsageEnv(out io.Writer, in interface{}) error {
|
|||||||
buf := bytes.NewBufferString("")
|
buf := bytes.NewBufferString("")
|
||||||
|
|
||||||
if err := ParseEnvWith(in, "", func(value reflect.Value, prefix string) error {
|
if err := ParseEnvWith(in, "", func(value reflect.Value, prefix string) error {
|
||||||
return usageValueEnv(buf, value, prefix)
|
return usageValueEnv(buf, value, prefix, usageFieldEnv)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -72,6 +75,21 @@ func UsageEnv(out io.Writer, in interface{}) error {
|
|||||||
return nil
|
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
|
// ParseWith parses with given structure interface and environment name prefix
|
||||||
// It is normally used in nested structure.
|
// It is normally used in nested structure.
|
||||||
// For example: we have such structure
|
// For example: we have such structure
|
||||||
@ -103,7 +121,9 @@ func ParseEnvWith(out interface{}, prefix string, parser ParseValueEnvFunc) erro
|
|||||||
return parser(valueOfStruct, prefix)
|
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
|
var err error
|
||||||
|
|
||||||
typeOfStruct := value.Type()
|
typeOfStruct := value.Type()
|
||||||
@ -120,22 +140,18 @@ func usageValueEnv(out io.Writer, value reflect.Value, prefix string) error {
|
|||||||
valueOfField.Interface(),
|
valueOfField.Interface(),
|
||||||
prefix+structOfField.Tag.Get("env"),
|
prefix+structOfField.Tag.Get("env"),
|
||||||
func(value reflect.Value, prefix string) error {
|
func(value reflect.Value, prefix string) error {
|
||||||
return usageValueEnv(out, value, prefix)
|
return usageValueEnv(out, value, prefix, usageField)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else if kindOfField == reflect.Struct {
|
} 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 {
|
if err == nil && kindOfField != reflect.Struct {
|
||||||
return err
|
err = usageField(out, structOfField, prefix)
|
||||||
}
|
|
||||||
|
|
||||||
if kindOfField != reflect.Struct {
|
|
||||||
err = usageFieldValueEnv(out, structOfField, prefix)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +272,7 @@ func setSimpleEnvValue(value reflect.Value, field reflect.StructField, str strin
|
|||||||
return err
|
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")
|
envName := field.Tag.Get("env")
|
||||||
if envName == "" {
|
if envName == "" {
|
||||||
return nil
|
return nil
|
||||||
@ -267,6 +283,8 @@ func usageFieldValueEnv(out io.Writer, field reflect.StructField, prefix string)
|
|||||||
|
|
||||||
if def := field.Tag.Get("default"); def != "" {
|
if def := field.Tag.Get("default"); def != "" {
|
||||||
msg += " (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 {
|
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
|
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))
|
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) {
|
func TestServiceLoginConfigEnv(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
12
makefile
12
makefile
@ -82,11 +82,8 @@ endif
|
|||||||
## Lint
|
## Lint
|
||||||
|
|
||||||
lint: ## Run all available linters.
|
lint: ## Run all available linters.
|
||||||
go vet ./...
|
@golangci-lint version
|
||||||
errcheck ./...
|
@golangci-lint run
|
||||||
staticcheck ./...
|
|
||||||
# usestdlibvars ./...
|
|
||||||
shadow ./...
|
|
||||||
@$(ECHO_CMD) "Lint\t\t${GREEN}[OK]${RESET}"
|
@$(ECHO_CMD) "Lint\t\t${GREEN}[OK]${RESET}"
|
||||||
.PHONY:lint
|
.PHONY:lint
|
||||||
|
|
||||||
@ -97,11 +94,6 @@ golangci-lint-install: ## Install golangci-lint util
|
|||||||
curl -sfL ${GOLANGCI_URL} | sh -s -- -b ${GOPATH}/bin ${GOLANGCI_VERSION}
|
curl -sfL ${GOLANGCI_URL} | sh -s -- -b ${GOPATH}/bin ${GOLANGCI_VERSION}
|
||||||
.PHONY:lint-golangci-install
|
.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
|
||||||
|
|
||||||
help: ## Show this help.
|
help: ## Show this help.
|
||||||
|
@ -39,8 +39,8 @@ type LogConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ServiceConfig struct {
|
type ServiceConfig struct {
|
||||||
Host string `cli:"hostname" env:"CONFIG_TEST_SERVICE_HOST" usage:"service hostname"`
|
Host string `cli:"hostname" env:"CONFIG_TEST_SERVICE_HOST" required:"true" usage:"service hostname"`
|
||||||
Port int `cli:"port" env:"CONFIG_TEST_SERVICE_PORT" usage:"service port"`
|
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"`
|
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"`
|
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"`
|
Log LogConfig `cli:"log" env:"CONFIG_TEST_SERVICE_LOG_" usage:"service log configuration"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user