Merge pull request #110 from foomo/feature/v0.11.0

feat: v0.11.0
This commit is contained in:
Kevin Franklin Kim 2025-04-04 16:41:17 +02:00 committed by GitHub
commit 8a61d79a9d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 315 additions and 247 deletions

View File

@ -25,7 +25,7 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: golangci/golangci-lint-action@v6
- uses: golangci/golangci-lint-action@v7
with:
version: latest

View File

@ -1,124 +1,14 @@
# yaml-language-server: $schema=https://golangci-lint.run/jsonschema/golangci.jsonschema.json
# https://golangci-lint.run/usage/configuration/
version: "2"
run:
go: 1.24.1
build-tags: [safe]
build-tags:
- safe
modules-download-mode: readonly
issues:
exclude-dirs:
- 'tmp'
exclude-rules:
- path: _test\.go
linters:
- forbidigo
- forcetypeassert
linters-settings:
misspell:
mode: restricted
asasalint:
ignore-test: true
# https://golangci-lint.run/usage/linters/#exhaustive
exhaustive:
default-signifies-exhaustive: true
# https://golangci-lint.run/usage/linters/#predeclared
predeclared:
ignore: "new,error"
# https://golangci-lint.run/usage/linters/#gocritic
gocritic:
disabled-checks:
- ifElseChain
- singleCaseSwitch
- commentFormatting
# https://golangci-lint.run/usage/linters/#testifylint
testifylint:
disable:
- float-compare
# https://golangci-lint.run/usage/linters/#gosec
gosec:
confidence: medium
# https://golangci-lint.run/usage/linters/#importas
importas:
no-unaliased: true
# https://golangci-lint.run/usage/linters/#gomoddirectives
gomoddirectives:
replace-local: true
replace-allow-list:
- github.com/c-bata/go-prompt
# https://golangci-lint.run/usage/linters/#staticcheck
staticcheck:
checks: ["all", "-SA1029"]
# https://golangci-lint.run/usage/linters/#revive
revive:
ignore-generated-header: true
enable-all-rules: true
rules:
- name: line-length-limit
disabled: true
- name: cognitive-complexity
disabled: true
- name: unused-parameter
disabled: true
- name: add-constant
disabled: true
- name: cyclomatic
disabled: true
- name: function-length
disabled: true
- name: function-result-limit
disabled: true
- name: flag-parameter
disabled: true
- name: unused-receiver
disabled: true
- name: argument-limit
disabled: true
- name: max-control-nesting
disabled: true
- name: comment-spacings
disabled: true
- name: struct-tag
arguments:
- "json,inline"
- name: unhandled-error
arguments:
- "fmt.Println"
# TODO remove
- name: use-any
disabled: true
- name: if-return
disabled: true
- name: deep-exit
disabled: true
- name: empty-block
disabled: true
- name: context-keys-type
disabled: true
- name: nested-structs
disabled: true
- name: unnecessary-stmt
disabled: true
- name: max-public-structs
disabled: true
- name: import-shadowing
disabled: true
- name: confusing-naming
disabled: true
- name: increment-decrement
disabled: true
- name: indent-error-flow
disabled: true
- name: unchecked-type-assertion
disabled: true
linters:
disable-all: true
default: none
enable:
## Default linters
- errcheck # errcheck is a program for checking for unchecked errors in Go code. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false]
- gosimple # (megacheck) Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false]
- govet # (vet, vetshadow) Vet examines Go source code and reports suspicious constructs. It is roughly the same as 'go vet' and uses its passes. [fast: false, auto-fix: false]
- ineffassign # Detects when assignments to existing variables are not used [fast: true, auto-fix: false]
- staticcheck # (megacheck) It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. [fast: false, auto-fix: false]
@ -129,7 +19,7 @@ linters:
- asciicheck # checks that all code identifiers does not have non-ASCII symbols in the name [fast: true, auto-fix: false]
- bidichk # Checks for dangerous unicode character sequences [fast: true, auto-fix: false]
- bodyclose # checks whether HTTP response body is closed successfully [fast: false, auto-fix: false]
- canonicalheader # canonicalheader checks whether net/http.Header uses canonical header [fast: false, auto-fix: false]
- canonicalheader # checks whether net/http.Header uses canonical header [fast: false, auto-fix: false]
#- containedctx # containedctx is a linter that detects struct contained context.Context field [fast: false, auto-fix: false]
- contextcheck # check whether the function uses a non-inherited context [fast: false, auto-fix: false]
#- copyloopvar # (go >= 1.22) copyloopvar is a linter detects places where loop variables are copied [fast: true, auto-fix: false]
@ -147,9 +37,7 @@ linters:
- gochecksumtype # Run exhaustiveness checks on Go "sum types" [fast: false, auto-fix: false]
- goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
- gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: true]
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true]
- goheader # Checks is file header matches to pattern [fast: true, auto-fix: true]
- goimports # Check import statements are formatted according to the 'goimport' command. Reformat imports in autofix mode. [fast: true, auto-fix: true]
- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false]
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false]
- goprintffuncname # Checks that printf-like functions are named with `f` at the end. [fast: true, auto-fix: false]
@ -181,7 +69,6 @@ linters:
- rowserrcheck # checks whether Rows.Err of rows is checked successfully [fast: false, auto-fix: false]
- spancheck # Checks for mistakes with OpenTelemetry/Census spans. [fast: false, auto-fix: false]
- sqlclosecheck # Checks that sql.Rows, sql.Stmt, sqlx.NamedStmt, pgx.Query are closed. [fast: false, auto-fix: false]
- stylecheck # Stylecheck is a replacement for golint [fast: false, auto-fix: false]
- testableexamples # linter checks if examples are testable (have an expected output) [fast: true, auto-fix: false]
- testifylint # Checks usage of github.com/stretchr/testify. [fast: false, auto-fix: false]
- testpackage # linter that makes you use a separate _test package [fast: true, auto-fix: false]
@ -199,10 +86,10 @@ linters:
#- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
#- dupl # Tool for code clone detection [fast: true, auto-fix: false]
#- dupword # checks for duplicate words in the source code [fast: true, auto-fix: false]
#- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
#- err113 # Go linter to check the errors handling expressions [fast: false, auto-fix: false]
#- exhaustruct # Checks if all structure fields are initialized [fast: false, auto-fix: false]
#- funlen # Tool for detection of long functions [fast: true, auto-fix: false]
#- gci # Gci controls Go package import order and makes it always deterministic. [fast: true, auto-fix: true]
#- ginkgolinter # enforces standards of using ginkgo and gomega [fast: false, auto-fix: false]
#- gochecknoglobals # Check that no global variables exist. [fast: false, auto-fix: false]
#- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
@ -210,7 +97,6 @@ linters:
#- gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]
#- godot # Check if comments end in a period [fast: true, auto-fix: true]
#- godox # Tool for detection of comment keywords [fast: true, auto-fix: false]
#- gofumpt # Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true]
#- interfacebloat # A linter that checks the number of methods inside an interface. [fast: true, auto-fix: false]
#- intrange # (go >= 1.22) intrange is a linter to find places where for loops could make use of an integer range. [fast: true, auto-fix: false]
#- ireturn # Accept Interfaces, Return Concrete Types [fast: false, auto-fix: false]
@ -230,3 +116,122 @@ linters:
#- wrapcheck # Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false]
#- wsl # add or remove empty lines [fast: true, auto-fix: false]
#- zerologlint # Detects the wrong usage of `zerolog` that a user forgets to dispatch with `Send` or `Msg` [fast: false, auto-fix: false]
settings:
exhaustive:
default-signifies-exhaustive: true
gocritic:
disabled-checks:
- ifElseChain
- singleCaseSwitch
- commentFormatting
gomoddirectives:
replace-allow-list:
- github.com/c-bata/go-prompt
replace-local: true
gosec:
confidence: medium
importas:
no-unaliased: true
misspell:
mode: restricted
predeclared:
ignore:
- new
- error
revive:
enable-all-rules: true
rules:
- name: line-length-limit
disabled: true
- name: cognitive-complexity
disabled: true
- name: unused-parameter
disabled: true
- name: add-constant
disabled: true
- name: cyclomatic
disabled: true
- name: function-length
disabled: true
- name: function-result-limit
disabled: true
- name: flag-parameter
disabled: true
- name: unused-receiver
disabled: true
- name: argument-limit
disabled: true
- name: max-control-nesting
disabled: true
- name: comment-spacings
disabled: true
- name: struct-tag
arguments:
- json,inline
- name: unhandled-error
arguments:
- fmt.Println
- name: use-any
disabled: true
- name: if-return
disabled: true
- name: deep-exit
disabled: true
- name: empty-block
disabled: true
- name: context-keys-type
disabled: true
- name: nested-structs
disabled: true
- name: unnecessary-stmt
disabled: true
- name: max-public-structs
disabled: true
- name: import-shadowing
disabled: true
- name: confusing-naming
disabled: true
- name: increment-decrement
disabled: true
- name: indent-error-flow
disabled: true
- name: unchecked-type-assertion
disabled: true
staticcheck:
checks:
- -SA1029
- all
testifylint:
disable:
- float-compare
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- forbidigo
- forcetypeassert
path: _test\.go
- linters:
- asasalint
path: (.+)_test\.go
paths:
- tmp
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- tmp
- third_party$
- builtin$
- examples$

18
go.mod
View File

@ -22,7 +22,7 @@ require (
github.com/samber/lo v1.49.1
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
github.com/spf13/viper v1.19.0
github.com/spf13/viper v1.20.1
github.com/stretchr/testify v1.10.0
golang.org/x/sync v0.12.0
gopkg.in/yaml.v3 v3.0.1
@ -49,37 +49,34 @@ require (
github.com/go-git/go-billy/v5 v5.6.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.25.0 // indirect
github.com/go-playground/validator/v10 v10.26.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-tty v0.0.7 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pkg/term v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sagikazarmark/locafero v0.9.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/afero v1.14.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
@ -87,13 +84,12 @@ require (
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/term v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect
)
replace github.com/c-bata/go-prompt v0.2.6 => github.com/franklinkim/go-prompt v0.2.7-0.20210427061716-a8f4995d7aa5

36
go.sum
View File

@ -90,8 +90,10 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
@ -105,8 +107,6 @@ github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQ
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@ -135,8 +135,6 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
@ -157,8 +155,6 @@ github.com/mattn/go-tty v0.0.7 h1:KJ486B6qI8+wBO7kQxYgmmEFDaFEE96JMBQ7h400N8Q=
github.com/mattn/go-tty v0.0.7/go.mod h1:f2i5ZOvXBU/tCABmLmOfzLz9azMo5wdAaElRNnJKr+k=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/neilotoole/slogt v1.1.0 h1:c7qE92sq+V0yvCuaxph+RQ2jOKL61c4hqS1Bv9W7FZE=
@ -191,10 +187,8 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
@ -207,16 +201,16 @@ github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnB
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -248,8 +242,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -306,8 +300,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -317,5 +309,5 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=

2
pkg/cache/cache.go vendored
View File

@ -2,6 +2,6 @@ package cache
type Cache interface {
Get(namespace string) Namespace
Clear(namespace string)
Clear(namespaces ...string)
List() map[string]Namespace
}

View File

@ -1,32 +1,43 @@
package cache
type MemoryCache map[string]MemoryNamespace
import (
"sync"
)
func NewMemoryCache() MemoryCache {
return MemoryCache{}
type MemoryCache struct {
store sync.Map
}
func (c MemoryCache) Clear(namespace string) {
if namespace == "" {
for _, value := range c {
value.Delete("")
}
} else {
c.Get(namespace).Delete("")
func NewMemoryCache() *MemoryCache {
return &MemoryCache{
store: sync.Map{},
}
}
func (c MemoryCache) Get(namespace string) Namespace {
if _, ok := c[namespace]; !ok {
c[namespace] = MemoryNamespace{}
func (c *MemoryCache) Clear(namespaces ...string) {
if len(namespaces) == 0 {
c.store.Range(func(key, value interface{}) bool {
namespaces = append(namespaces, key.(string)) //nolint:forcetypeassert
return true
})
}
for _, namespace := range namespaces {
c.Get(namespace).Delete()
}
return c[namespace]
}
func (c MemoryCache) List() map[string]Namespace {
func (c *MemoryCache) Get(namespace string) Namespace {
value, _ := c.store.LoadOrStore(namespace, &MemoryNamespace{
store: sync.Map{},
})
return value.(*MemoryNamespace) //nolint:forcetypeassert
}
func (c *MemoryCache) List() map[string]Namespace {
ret := map[string]Namespace{}
for s, namespace := range c {
ret[s] = namespace
}
c.store.Range(func(k, v interface{}) bool {
ret[k.(string)] = v.(*MemoryNamespace) //nolint:forcetypeassert
return true
})
return ret
}

View File

@ -1,38 +1,44 @@
package cache
import "github.com/c-bata/go-prompt"
import (
"sync"
type MemoryNamespace map[string]interface{}
"github.com/c-bata/go-prompt"
)
func (c MemoryNamespace) Delete(key string) {
if key == "" {
for key := range c {
delete(c, key)
}
type MemoryNamespace struct {
store sync.Map
}
func (c *MemoryNamespace) Delete(keys ...string) {
if len(keys) == 0 {
c.store.Clear()
} else {
delete(c, key)
}
}
func (c MemoryNamespace) Get(key string, cb func() interface{}) interface{} {
if _, ok := c[key]; !ok {
if cb == nil {
return nil
for _, key := range keys {
c.store.Delete(key)
}
c[key] = cb()
}
return c[key]
}
func (c MemoryNamespace) Keys() []string {
keys := make([]string, 0, len(c))
for k := range c {
keys = append(keys, k)
func (c *MemoryNamespace) Get(key string, cb func() any) any {
value, ok := c.store.Load(key)
if !ok && cb != nil {
value = cb()
c.store.Store(key, value)
}
return value
}
func (c *MemoryNamespace) Keys() []string {
var keys []string
c.store.Range(func(k, v interface{}) bool {
keys = append(keys, k.(string)) //nolint:forcetypeassert
return true
})
return keys
}
func (c MemoryNamespace) GetSuggests(key string, cb func() interface{}) []prompt.Suggest {
func (c *MemoryNamespace) GetSuggests(key string, cb func() any) []prompt.Suggest {
if v, ok := c.Get(key, cb).([]prompt.Suggest); ok {
return v
}

View File

@ -7,6 +7,6 @@ import (
type Namespace interface {
Get(key string, cb func() any) any
Keys() []string
Delete(key string)
Delete(keys ...string)
GetSuggests(key string, cb func() any) []prompt.Suggest
}

View File

@ -106,7 +106,7 @@ func (c *Cache) clear(ctx context.Context, r *readline.Readline) error {
}
} else {
c.l.Info("clearing all caches")
c.cache.Clear("")
c.cache.Clear()
}
return nil
}

View File

@ -107,8 +107,23 @@ func (c *Env) list(ctx context.Context, r *readline.Readline) error {
data := pterm.TableData{{"Name", "Value"}}
values := os.Environ()
sort.Strings(values)
var pairs [][]string
for _, s := range values {
data = append(data, strings.SplitN(s, "=", 2))
pairs = append(pairs, strings.SplitN(s, "=", 2))
}
return pterm.DefaultTable.WithHasHeader(true).WithData(data).Render()
var maxKeyLen int
for _, pair := range pairs {
maxKeyLen = max(maxKeyLen, len(pair[0]))
}
maxValueLen := pterm.GetTerminalWidth() - maxKeyLen - 5
for i, pair := range pairs {
var value string
for len(pair[1]) > maxValueLen {
value += pair[1][:maxValueLen] + "\n"
pair[1] = pair[1][maxValueLen:]
}
pairs[i][1] = value + pair[1]
}
data = append(data, pairs...)
return pterm.DefaultTable.WithHasHeader(true).WithHeaderRowSeparator("-").WithData(data).Render()
}

View File

@ -44,9 +44,10 @@ func (c *Node) setFlags(ctx context.Context, r *readline.Readline, parse bool) e
func (c *Node) completeArguments(ctx context.Context, p *root, r *readline.Readline, i int) []goprompt.Suggest {
var suggest []goprompt.Suggest
localArgs := r.Args()[i:]
localArgs := r.Args().From(i)
switch {
case len(c.Nodes) > 0 && len(localArgs) <= 1:
case len(c.Nodes) > 0:
for _, command := range c.Nodes {
if command.Values != nil {
suggest = command.Values(ctx, r)
@ -54,12 +55,12 @@ func (c *Node) completeArguments(ctx context.Context, p *root, r *readline.Readl
suggest = append(suggest, goprompt.Suggest{Text: command.Name, Description: command.Description})
}
}
case len(c.Args) > 0 && len(c.Args) >= len(localArgs):
j := len(localArgs)
if len(localArgs) > 0 && localArgs[j-1] != "" {
j -= 1
case len(c.Args) > 0 && len(localArgs) == 0:
if fn := c.Args[0].Suggest; fn != nil {
suggest = fn(ctx, p, r)
}
if fn := c.Args[j].Suggest; fn != nil {
case len(c.Args) > 0 && len(c.Args) >= len(localArgs):
if fn := c.Args[len(localArgs)-1].Suggest; fn != nil {
suggest = fn(ctx, p, r)
}
case len(c.Args) > 0 && c.Args.Last().Repeat && c.Args.Last().Suggest != nil:
@ -85,7 +86,7 @@ func (c *Node) completeFlags(r *readline.Readline) []goprompt.Suggest {
}
func (c *Node) execute(ctx context.Context, r *readline.Readline, i int) error {
localArgs := r.Args()[i:]
localArgs := r.Args().From(i)
// validate
switch {
@ -115,7 +116,7 @@ func (c *Node) find(ctx context.Context, r *readline.Readline, i int) (*Node, in
if subCmd, j := cmd.find(ctx, r, i+1); subCmd != nil {
return subCmd, j
}
return cmd, i
return cmd, i + 1
}
if cmd.Values != nil {
for _, name := range cmd.Values(ctx, r) {
@ -123,7 +124,7 @@ func (c *Node) find(ctx context.Context, r *readline.Readline, i int) (*Node, in
if subCmd, j := cmd.find(ctx, r, i+1); subCmd != nil {
return subCmd, j
}
return cmd, i
return cmd, i + 1
}
}
}

View File

@ -60,7 +60,7 @@ func (t *root) Complete(ctx context.Context, r *readline.Readline) []goprompt.Su
} else if err := cmd.setFlags(ctx, r, false); err != nil {
return nil
} else {
suggests = cmd.completeArguments(ctx, t, r, i+1)
suggests = cmd.completeArguments(ctx, t, r, i)
}
case readline.ModeFlags:
if cmd, _ := t.node.find(ctx, r, 0); cmd == nil && t.node != nil {

View File

@ -426,5 +426,5 @@ func T(ctx context.Context) *testing.T {
func SetT(ctx context.Context, t *testing.T) context.Context {
t.Helper()
return context.WithValue(ctx, "t", t)
return context.WithValue(ctx, "t", t) //nolint:staticcheck
}

View File

@ -2,10 +2,11 @@ package config
type (
Prompt struct {
Title string `json:"title" yaml:"title"`
Prefix string `json:"prefix" yaml:"prefix"`
History PromptHistory `json:"history" yaml:"history"`
Aliases map[string]string `json:"aliases" yaml:"aliases"`
Title string `json:"title" yaml:"title"`
Prefix string `json:"prefix" yaml:"prefix"`
PrefixGit bool `json:"prefixGit" yaml:"prefixGit"`
History PromptHistory `json:"history" yaml:"history"`
Aliases map[string]string `json:"aliases" yaml:"aliases"`
}
PromptHistory struct {
Limit int `json:"limit" yaml:"limit"`

View File

@ -7,6 +7,7 @@ import (
"github.com/c-bata/go-prompt"
"github.com/c-bata/go-prompt/completer"
"github.com/foomo/posh/pkg/command"
"github.com/foomo/posh/pkg/env"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/check"
"github.com/foomo/posh/pkg/prompt/flair"
@ -14,22 +15,24 @@ import (
"github.com/foomo/posh/pkg/prompt/history"
"github.com/foomo/posh/pkg/readline"
"github.com/foomo/posh/pkg/shell"
"github.com/go-git/go-git/v5"
)
type (
Prompt struct {
l log.Logger
ctx context.Context
title string
flair flair.Flair
prefix string
check check.Check
checkers []check.Checker
filter goprompt.Filter
readline *readline.Readline
history history.History
commands command.Commands
aliases map[string]string
l log.Logger
ctx context.Context
title string
flair flair.Flair
prefix string
prefixGit bool
check check.Check
checkers []check.Checker
filter goprompt.Filter
readline *readline.Readline
history history.History
commands command.Commands
aliases map[string]string
// inputRegex - split cmd into args
promptOptions []prompt.Option
}
@ -56,7 +59,14 @@ func WithFlair(v flair.Flair) Option {
func WithPrefix(v string) Option {
return func(o *Prompt) error {
o.prefix = v + " "
o.prefix = v + " "
return nil
}
}
func WithPrefixGit(v bool) Option {
return func(o *Prompt) error {
o.prefixGit = v
return nil
}
}
@ -134,15 +144,16 @@ func WithPromptOptions(v ...prompt.Option) Option {
func New(l log.Logger, opts ...Option) (*Prompt, error) {
inst := &Prompt{
l: l.Named("prompt"),
ctx: context.Background(),
title: "posh",
prefix: ">",
flair: flair.DefaultFlair,
filter: goprompt.FilterFuzzy,
check: check.DefaultCheck,
history: history.NewNoop(l),
commands: command.Commands{},
l: l.Named("prompt"),
ctx: context.Background(),
title: "posh",
prefix: " ",
prefixGit: false,
flair: flair.DefaultFlair,
filter: goprompt.FilterFuzzy,
check: check.DefaultCheck,
history: history.NewNoop(l),
commands: command.Commands{},
}
for _, opt := range opts {
if opt != nil {
@ -187,6 +198,20 @@ func (s *Prompt) Run() error {
[]prompt.Option{
prompt.OptionTitle(s.title),
prompt.OptionPrefix(s.prefix),
prompt.OptionLivePrefix(func() (string, bool) {
if s.prefixGit {
r, err := git.PlainOpen(env.ProjectRoot())
if err != nil {
s.l.Debug("failed to open git repository", "error", err)
}
ref, err := r.Head()
if err != nil {
s.l.Debug("failed to fetch HEAD", "error", err)
}
return s.prefix[:len(s.prefix)-4] + "(" + ref.Name().Short() + ") ", true
}
return "", false
}),
prompt.OptionPrefixTextColor(prompt.Cyan),
prompt.OptionInputTextColor(prompt.DefaultColor),
prompt.OptionCompletionWordSeparator(completer.FilePathCompletionSeparator),
@ -253,7 +278,7 @@ func (s *Prompt) execute(input string) {
if cmd := s.Commands().Get(s.readline.Cmd()); cmd != nil {
s.l.Debugf(`executing command:
> %s
%s
%s
`, input, s.readline.String())
@ -263,11 +288,17 @@ func (s *Prompt) execute(input string) {
return
}
}
if err := cmd.Execute(ctx, s.readline); err != nil {
if err := cmd.Execute(ctx, s.readline); err != nil && err.Error() == "signal: interrupt" {
s.l.Debug(err.Error())
} else if err != nil {
s.l.Error(err.Error())
}
} else {
if err := shell.New(ctx, s.l, input).Run(); err != nil && err.Error() == "signal: interrupt" {
s.l.Debug(err.Error())
} else if err != nil {
s.l.Error(err.Error())
}
} else if err := shell.New(ctx, s.l, input).Run(); err != nil {
s.l.Error(err.Error())
}
}

View File

@ -29,7 +29,7 @@ func (s *FlagSet) SetValues(name string, values ...string) error {
}
func (s *FlagSet) GetValues(name string) []string {
if f := s.FlagSet.Lookup(name); f == nil {
if f := s.Lookup(name); f == nil {
return nil
} else if v, ok := f.Annotations["values"]; ok {
return v

View File

@ -16,6 +16,7 @@ type Shell struct {
l log.Logger
cmd *exec.Cmd
quiet bool
debug bool
args []string
stdin io.Reader
stdout io.Writer
@ -88,6 +89,11 @@ func (s *Shell) Stderr(v io.Writer) *Shell {
return s
}
func (s *Shell) Debug() *Shell {
s.debug = true
return s
}
func (s *Shell) Run() error {
args := s.args
s.cmd.Args = append(s.cmd.Args, strings.Join(args, " "))
@ -144,15 +150,19 @@ func (s *Shell) Wait() error {
// ------------------------------------------------------------------------------------------------
func (s *Shell) trace() {
s.l.Tracef(`"Executing:
if s.debug {
s.l.Info(s.cmd.String())
} else {
s.l.Tracef(`"Executing:
$ %s
Directory: %s
%s
`,
s.cmd.String(),
s.cmd.Dir,
strings.Join(s.cmd.Environ(), "\n"),
)
s.cmd.String(),
s.cmd.Dir,
strings.Join(s.cmd.Environ(), "\n"),
)
}
}