Skip to content

Commit d1c6678

Browse files
phm07jooola
andauthored
feat: new configuration system, config subcommand (#736)
This PR implements the new configuration system as described in #762. Closes #762 In preparation for #434 --------- Co-authored-by: pauhull <[email protected]> Co-authored-by: Jonas L. <[email protected]>
1 parent fa9b366 commit d1c6678

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+3357
-370
lines changed

README.md

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,18 +142,31 @@ You can control output via the `-o` option:
142142
The template’s input is the resource’s corresponding struct in the
143143
[hcloud-go](https://godoc.org/github.com/hetznercloud/hcloud-go/hcloud) library.
144144

145-
## Configure hcloud using environment variables
146-
147-
You can use the following environment variables to configure `hcloud`:
148-
149-
* `HCLOUD_TOKEN`
150-
* `HCLOUD_CONTEXT`
151-
* `HCLOUD_CONFIG`
152-
153-
When using `hcloud` in scripts, for example, it may be cumbersome to work with
154-
contexts. Instead of creating a context, you can set the token via the `HCLOUD_TOKEN`
155-
environment variable. When combined with tools like [direnv](https://direnv.net), you
156-
can configure a per-directory context by setting `HCLOUD_CONTEXT=my-context` via `.envrc`.
145+
## Configuring hcloud
146+
147+
The hcloud CLI tool can be configured using following methods:
148+
1. Configuration file
149+
2. Environment variables
150+
3. Command line flags
151+
152+
A higher number means a higher priority. For example, a command line flag will
153+
always override an environment variable.
154+
155+
The configuration file is located at `~/.config/hcloud/cli.toml` by default
156+
(On Windows: `%APPDATA%\hcloud\cli.toml`). You can change the location by setting
157+
the `HCLOUD_CONFIG` environment variable or the `--config` flag. The configuration file
158+
stores global preferences, the currently active context, all contexts and
159+
context-specific preferences. Contexts always store a token and can optionally have
160+
additional preferences which take precedence over the globally set preferences.
161+
162+
However, a config file is not required. If no config file is found, the CLI will
163+
use the default configuration. Overriding options using environment variables allows the
164+
hcloud CLI to function in a stateless way. For example, setting `HCLOUD_TOKEN` is
165+
already enough in many cases.
166+
167+
You can use the `hcloud config` command to manage your configuration, for example
168+
to get, list, set and unset configuration options and preferences. You can view a list
169+
of all available options and preferences by running `hcloud config --help`.
157170

158171
## Examples
159172

cmd/hcloud/main.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/hetznercloud/cli/internal/cmd/all"
99
"github.com/hetznercloud/cli/internal/cmd/certificate"
1010
"github.com/hetznercloud/cli/internal/cmd/completion"
11+
configCmd "github.com/hetznercloud/cli/internal/cmd/config"
1112
"github.com/hetznercloud/cli/internal/cmd/context"
1213
"github.com/hetznercloud/cli/internal/cmd/datacenter"
1314
"github.com/hetznercloud/cli/internal/cmd/firewall"
@@ -37,14 +38,10 @@ func init() {
3738
}
3839

3940
func main() {
40-
configPath := os.Getenv("HCLOUD_CONFIG")
41-
if configPath == "" {
42-
configPath = config.DefaultConfigPath()
43-
}
4441

45-
cfg, err := config.ReadConfig(configPath)
46-
if err != nil {
47-
log.Fatalf("unable to read config file %q: %s\n", configPath, err)
42+
cfg := config.New()
43+
if err := cfg.Read(nil); err != nil {
44+
log.Fatalf("unable to read config file \"%s\": %s\n", cfg.Path(), err)
4845
}
4946

5047
s, err := state.New(cfg)
@@ -78,6 +75,7 @@ func main() {
7875
version.NewCommand(s),
7976
completion.NewCommand(s),
8077
context.NewCommand(s),
78+
configCmd.NewCommand(s),
8179
)
8280

8381
if err := rootCommand.Execute(); err != nil {

go.mod

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,51 @@ require (
1212
github.com/golang/mock v1.6.0
1313
github.com/guptarohit/asciigraph v0.7.1
1414
github.com/hetznercloud/hcloud-go/v2 v2.9.0
15+
github.com/jedib0t/go-pretty/v6 v6.5.9
1516
github.com/pelletier/go-toml/v2 v2.2.2
1617
github.com/spf13/cobra v1.8.0
1718
github.com/spf13/pflag v1.0.5
19+
github.com/spf13/viper v1.18.2
1820
github.com/stretchr/testify v1.9.0
1921
golang.org/x/crypto v0.23.0
20-
golang.org/x/term v0.21.0
22+
golang.org/x/term v0.20.0
2123
)
2224

2325
require (
2426
github.com/VividCortex/ewma v1.2.0 // indirect
2527
github.com/beorn7/perks v1.0.1 // indirect
2628
github.com/cespare/xxhash/v2 v2.2.0 // indirect
27-
github.com/davecgh/go-spew v1.1.1 // indirect
29+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
30+
github.com/fsnotify/fsnotify v1.7.0 // indirect
31+
github.com/hashicorp/hcl v1.0.0 // indirect
2832
github.com/inconshreveable/mousetrap v1.1.0 // indirect
33+
github.com/magiconair/properties v1.8.7 // indirect
2934
github.com/mattn/go-colorable v0.1.13 // indirect
3035
github.com/mattn/go-isatty v0.0.20 // indirect
3136
github.com/mattn/go-runewidth v0.0.15 // indirect
32-
github.com/pmezard/go-difflib v1.0.0 // indirect
37+
github.com/mitchellh/mapstructure v1.5.0 // indirect
38+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
3339
github.com/prometheus/client_golang v1.19.1 // indirect
3440
github.com/prometheus/client_model v0.5.0 // indirect
3541
github.com/prometheus/common v0.48.0 // indirect
3642
github.com/prometheus/procfs v0.12.0 // indirect
3743
github.com/rivo/uniseg v0.2.0 // indirect
44+
github.com/sagikazarmark/locafero v0.4.0 // indirect
45+
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
46+
github.com/sourcegraph/conc v0.3.0 // indirect
47+
github.com/spf13/afero v1.11.0 // indirect
48+
github.com/spf13/cast v1.6.0 // indirect
49+
github.com/subosito/gotenv v1.6.0 // indirect
50+
go.uber.org/atomic v1.9.0 // indirect
51+
go.uber.org/multierr v1.9.0 // indirect
52+
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
3853
golang.org/x/mod v0.14.0 // indirect
3954
golang.org/x/net v0.25.0 // indirect
40-
golang.org/x/sys v0.21.0 // indirect
55+
golang.org/x/sys v0.20.0 // indirect
4156
golang.org/x/text v0.15.0 // indirect
4257
golang.org/x/tools v0.17.0 // indirect
4358
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
4459
google.golang.org/protobuf v1.33.0 // indirect
60+
gopkg.in/ini.v1 v1.67.0 // indirect
4561
gopkg.in/yaml.v3 v3.0.1 // indirect
4662
)

go.sum

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,19 @@ github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk=
1010
github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI=
1111
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
1212
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
13-
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1413
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
14+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
15+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1516
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
1617
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
1718
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
1819
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
1920
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
2021
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
22+
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
23+
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
24+
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
25+
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
2126
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
2227
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
2328
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
@@ -32,27 +37,36 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
3237
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
3338
github.com/guptarohit/asciigraph v0.7.1 h1:K+JWbRc04XEfv8BSZgNuvhCmpbvX4+9NYd/UxXVnAuk=
3439
github.com/guptarohit/asciigraph v0.7.1/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag=
40+
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
41+
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
3542
github.com/hetznercloud/hcloud-go/v2 v2.9.0 h1:s0N6R7Zoi2DPfMtUF5o9VeUBzTtHVY6MIkHOQnfu/AY=
3643
github.com/hetznercloud/hcloud-go/v2 v2.9.0/go.mod h1:qtW/TuU7Bs16ibXl/ktJarWqU2LwHr7eGlwoilHxtgg=
3744
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
3845
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
46+
github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+UV8OU=
47+
github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
3948
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
4049
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
4150
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
4251
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
4352
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
4453
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
54+
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
55+
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
4556
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
4657
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
4758
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
4859
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
4960
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
5061
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
5162
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
63+
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
64+
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
5265
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
5366
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
54-
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5567
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
68+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
69+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5670
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
5771
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
5872
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
@@ -66,26 +80,47 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
6680
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
6781
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
6882
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
83+
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
84+
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
85+
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
86+
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
87+
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
88+
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
89+
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
90+
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
91+
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
92+
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
6993
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
7094
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
7195
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
7296
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
97+
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
98+
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
7399
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
74100
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
75101
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
76102
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
103+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
77104
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
78105
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
79106
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
80107
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
81108
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
82109
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
110+
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
111+
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
83112
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
84113
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
114+
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
115+
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
116+
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
117+
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
85118
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
86119
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
87120
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
88121
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
122+
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
123+
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
89124
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
90125
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
91126
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
@@ -108,11 +143,11 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
108143
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
109144
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
110145
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
111-
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
112-
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
146+
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
147+
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
113148
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
114-
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
115-
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
149+
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
150+
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
116151
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
117152
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
118153
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
@@ -134,6 +169,8 @@ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh
134169
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
135170
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
136171
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
172+
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
173+
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
137174
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
138175
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
139176
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/cli/root.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ package cli
22

33
import (
44
"os"
5-
"time"
65

76
"github.com/spf13/cobra"
87

98
"github.com/hetznercloud/cli/internal/state"
10-
"github.com/hetznercloud/hcloud-go/v2/hcloud"
9+
"github.com/hetznercloud/cli/internal/state/config"
1110
)
1211

1312
func NewRootCommand(s state.State) *cobra.Command {
@@ -20,18 +19,13 @@ func NewRootCommand(s state.State) *cobra.Command {
2019
SilenceErrors: true,
2120
DisableFlagsInUseLine: true,
2221
}
23-
cmd.PersistentFlags().Duration("poll-interval", 500*time.Millisecond, "Interval at which to poll information, for example action progress")
24-
cmd.PersistentFlags().Bool("quiet", false, "Only print error messages")
2522

26-
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
27-
pollInterval, err := cmd.Flags().GetDuration("poll-interval")
28-
if err != nil {
29-
return err
30-
}
31-
s.Client().WithOpts(hcloud.WithPollBackoffFunc(hcloud.ConstantBackoff(pollInterval)))
23+
cmd.PersistentFlags().AddFlagSet(s.Config().FlagSet())
3224

25+
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
26+
var err error
3327
out := os.Stdout
34-
if quiet, _ := cmd.Flags().GetBool("quiet"); quiet {
28+
if quiet := config.OptionQuiet.Get(s.Config()); quiet {
3529
out, err = os.Open(os.DevNull)
3630
if err != nil {
3731
return err

internal/cmd/base/create.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/hetznercloud/cli/internal/cmd/util"
1010
"github.com/hetznercloud/cli/internal/hcapi2"
1111
"github.com/hetznercloud/cli/internal/state"
12+
"github.com/hetznercloud/cli/internal/state/config"
1213
)
1314

1415
// CreateCmd allows defining commands for resource creation
@@ -42,7 +43,7 @@ func (cc *CreateCmd) CobraCommand(s state.State) *cobra.Command {
4243
cmd.RunE = func(cmd *cobra.Command, args []string) error {
4344
outputFlags := output.FlagsForCommand(cmd)
4445

45-
quiet, _ := cmd.Flags().GetBool("quiet")
46+
quiet := config.OptionQuiet.Get(s.Config())
4647

4748
isSchema := outputFlags.IsSet("json") || outputFlags.IsSet("yaml")
4849
if isSchema && !quiet {

internal/cmd/cmpl/suggestions.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,14 @@ func SuggestArgs(
9393
return f(cmd, args, toComplete)
9494
}
9595
}
96+
97+
// NoFileCompletion returns a function that provides completion suggestions without
98+
// file completion.
99+
func NoFileCompletion(f func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)) func(
100+
*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
101+
102+
return func(command *cobra.Command, i []string, s string) ([]string, cobra.ShellCompDirective) {
103+
candidates, _ := f(command, i, s)
104+
return candidates, cobra.ShellCompDirectiveNoFileComp
105+
}
106+
}

0 commit comments

Comments
 (0)