Skip to content

Commit 4740032

Browse files
authored
refactor: cli config rework and pagination tweaks (#1854)
1 parent b89fe2a commit 4740032

File tree

35 files changed

+2994
-328
lines changed

35 files changed

+2994
-328
lines changed

cli/README.md

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@ CLI versions are tagged as `cli/vX.Y.Z` in the main repo. Use module tags to pin
2727

2828
The CLI stores config in `~/.config/arcanecli.yml`.
2929

30+
Create a starter config file (all supported keys):
31+
32+
- `arcane config init`
33+
- `arcane config backup` (moves current config to `~/.config/arcanecli.yml.bak`)
34+
3035
Set the Arcane server URL:
3136

32-
- `arcane config set --server-url http://localhost:3552`
37+
- `arcane config set server-url http://localhost:3552`
3338

3439
### Authenticate (choose one)
3540

@@ -39,4 +44,50 @@ Set the Arcane server URL:
3944

4045
#### Option B: API key
4146

42-
- `arcane config set --api-key arc_xxxxxxxxxxxxx`
47+
- `arcane config set api-key arc_xxxxxxxxxxxxx`
48+
49+
## Useful Global Flags
50+
51+
- `--output text|json` for output mode (`--json` is an alias for `--output json`)
52+
- `--env <id>` to override the configured default environment for one command
53+
- `--yes` to auto-confirm destructive prompts
54+
- `--no-color` to disable ANSI color output
55+
- `--request-timeout <duration>` to override HTTP timeout per command
56+
57+
## Utilities
58+
59+
- `arcane completion bash|zsh|fish|powershell` to generate shell completions
60+
- `arcane doctor` to run local CLI diagnostics
61+
62+
## Pagination Config
63+
64+
Set global and per-resource list limits in config:
65+
66+
```yaml
67+
pagination:
68+
default:
69+
limit: 25
70+
resources:
71+
containers:
72+
limit: 50
73+
images:
74+
limit: 100
75+
volumes:
76+
limit: 40
77+
networks:
78+
limit: 40
79+
```
80+
81+
CLI precedence is:
82+
1. `--limit`
83+
2. `pagination.resources.<resource>.limit`
84+
3. `pagination.default.limit`
85+
4. command built-in default
86+
87+
You can configure limits with:
88+
- `arcane config set default-limit 25`
89+
- `arcane config set pagination.resources.containers.limit 50 pagination.resources.images.limit 100`
90+
91+
Legacy flag syntax remains supported:
92+
- `arcane config set --default-limit 25`
93+
- `arcane config set --resource-limit containers=50 --resource-limit images=100`

cli/go.mod

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ require (
1010
github.com/charmbracelet/x/term v0.2.2
1111
github.com/fatih/color v1.18.0
1212
github.com/getarcaneapp/arcane/types v1.15.3
13+
github.com/go-viper/mapstructure/v2 v2.5.0
1314
github.com/mattn/go-runewidth v0.0.20
1415
github.com/sirupsen/logrus v1.9.4
1516
github.com/spf13/cobra v1.10.2
17+
github.com/spf13/viper v1.21.0
1618
go.withmatt.com/size v0.0.0-20250220224316-11aee5773e67
17-
gopkg.in/yaml.v3 v3.0.1
1819
)
1920

2021
require (
@@ -38,9 +39,8 @@ require (
3839
github.com/docker/go-connections v0.6.0 // indirect
3940
github.com/docker/go-units v0.5.0 // indirect
4041
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
41-
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
42+
github.com/fsnotify/fsnotify v1.9.0 // indirect
4243
github.com/inconshreveable/mousetrap v1.1.0 // indirect
43-
github.com/kr/pretty v0.3.1 // indirect
4444
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
4545
github.com/mattn/go-colorable v0.1.14 // indirect
4646
github.com/mattn/go-isatty v0.0.20 // indirect
@@ -56,12 +56,19 @@ require (
5656
github.com/muesli/termenv v0.16.0 // indirect
5757
github.com/opencontainers/go-digest v1.0.0 // indirect
5858
github.com/opencontainers/image-spec v1.1.1 // indirect
59+
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
5960
github.com/rivo/uniseg v0.4.7 // indirect
6061
github.com/rogpeppe/go-internal v1.14.1 // indirect
62+
github.com/sagikazarmark/locafero v0.11.0 // indirect
6163
github.com/sahilm/fuzzy v0.1.1 // indirect
64+
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
65+
github.com/spf13/afero v1.15.0 // indirect
66+
github.com/spf13/cast v1.10.0 // indirect
6267
github.com/spf13/pflag v1.0.10 // indirect
68+
github.com/subosito/gotenv v1.6.0 // indirect
6369
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
6470
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
71+
go.yaml.in/yaml/v3 v3.0.4 // indirect
6572
go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect
6673
golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
6774
golang.org/x/sync v0.19.0 // indirect

cli/go.sum

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ github.com/clipperhouse/displaywidth v0.9.0/go.mod h1:aCAAqTlh4GIVkhQnJpbL0T/Wfc
3939
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
4040
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
4141
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
42+
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
4243
github.com/compose-spec/compose-go/v2 v2.10.1 h1:mFbXobojGRFIVi1UknrvaDAZ+PkJfyjqkA1yseh+vAU=
4344
github.com/compose-spec/compose-go/v2 v2.10.1/go.mod h1:Ohac1SzhO/4fXXrzWIztIVB6ckmKBv1Nt5Z5mGVESUg=
4445
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
45-
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
4646
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
4747
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4848
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
@@ -57,6 +57,10 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6
5757
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
5858
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
5959
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
60+
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
61+
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
62+
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
63+
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
6064
github.com/getarcaneapp/arcane/types v1.15.3 h1:UMhhWPNvy+lGVdg+5w9b47hr83aMe2KfV6dJIs4RHZY=
6165
github.com/getarcaneapp/arcane/types v1.15.3/go.mod h1:kqkuqZZ9TkfWOvAuzCKq5UTX/11NO77lyPg5ECJrMXo=
6266
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
@@ -106,32 +110,45 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
106110
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
107111
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
108112
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
109-
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
113+
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
114+
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
110115
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
111116
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
112117
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
113118
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
114-
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
115119
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
116120
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
117121
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
122+
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
123+
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
118124
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
119125
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
120126
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
121127
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
128+
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
129+
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
130+
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
131+
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
132+
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
133+
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
122134
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
123135
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
124136
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
125137
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
126138
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
139+
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
140+
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
127141
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
128142
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
143+
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
144+
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
129145
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
130146
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
131147
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
132148
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
133149
go.withmatt.com/size v0.0.0-20250220224316-11aee5773e67 h1:nHPqmzoLZv+9OqER7S2oXnIBDAbIaIKKrVtNtDvJzjc=
134150
go.withmatt.com/size v0.0.0-20250220224316-11aee5773e67/go.mod h1:WFmSrzphcXaSV4LG3YfIw42bPHDK8A6WsAYZCxyys/c=
151+
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
135152
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
136153
go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go=
137154
go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package benchmark
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"net/http"
8+
"net/http/httptest"
9+
"testing"
10+
11+
"github.com/getarcaneapp/arcane/cli/internal/client"
12+
clitypes "github.com/getarcaneapp/arcane/cli/internal/types"
13+
)
14+
15+
func BenchmarkClientListMediumPayload(b *testing.B) {
16+
payload := make(map[string]any, 0)
17+
items := make([]map[string]any, 0, 200)
18+
for i := 0; i < 200; i++ {
19+
items = append(items, map[string]any{
20+
"id": fmt.Sprintf("id-%d", i),
21+
"name": fmt.Sprintf("name-%d", i),
22+
"state": "running",
23+
})
24+
}
25+
payload["success"] = true
26+
payload["data"] = items
27+
payload["pagination"] = map[string]any{
28+
"currentPage": 1,
29+
"itemsPerPage": 200,
30+
"totalItems": 200,
31+
"totalPages": 1,
32+
}
33+
raw, _ := json.Marshal(payload)
34+
35+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
36+
w.Header().Set("Content-Type", "application/json")
37+
_, _ = w.Write(raw)
38+
}))
39+
defer srv.Close()
40+
41+
cfg := &clitypes.Config{ServerURL: srv.URL, APIKey: "arc_test_key"}
42+
c, err := client.New(cfg)
43+
if err != nil {
44+
b.Fatalf("new client: %v", err)
45+
}
46+
47+
b.ResetTimer()
48+
for i := 0; i < b.N; i++ {
49+
resp, err := c.Get(context.Background(), "/api/environments/0/containers?limit=200")
50+
if err != nil {
51+
b.Fatalf("request: %v", err)
52+
}
53+
_ = resp.Body.Close()
54+
}
55+
}

0 commit comments

Comments
 (0)